読者です 読者をやめる 読者になる 読者になる

mmag

ハマったことメモなど

遅いと思ったからといってすぐspawnするのはダメ

Elixir Phoenix

昨日は遅いと思ったらとりあえずspawnとか言っていたのが、そうもいかなくなりましたという話。

昨日書いたやつがこれ。Rails Tutorialに沿って書いている。

## priv/repo/seeds.exs

alias PhMicroblog.{User, Repo}

defmodule Helper do
  def insert_user!(name, email, password) do
    params = %{
      name: name,
      email: email,
      password: password,
      password_confirmation: password
    }

    %User{} |> User.changeset(params) |> Repo.insert!
  end
end

Faker.start

Helper.insert_user!("Example User", "example@railstutorial.org", "foobar")

Enum.each 1..99, fn i ->
  spawn fn ->
    Helper.insert_user!(Faker.Name.name, "example-#{i}@railstutorial.org", "password")
  end
end

これはユーザを100人つくるseedでしたが、この後Micropostというものが出現し、それを300個ほど作りましょうという話になりました。Elixirに書き直すとこんな感じ。適当なcontentをつくってはユーザ6人にMicropostをつくる。それを50回。

Helper.insert_user!("Example User", "example@railstutorial.org", "foobar")

Enum.each 1..99, fn i ->
  spawn fn ->
    Helper.insert_user!(Faker.Name.name, "example-#{i}@railstutorial.org", "password")
  end
end

users = from(u in User, order_by: :inserted_at, limit: 6) |> Repo.all

Enum.each 1..50, fn _i ->
  content = Faker.Lorem.sentence(5)
  Enum.each users, fn user ->
    user |> build_assoc(:microposts) |> Micropost.changeset(%{content: content}) |> Repo.insert!
  end
end

だがしかしこれだと、

users = from(u in User, order_by: :inserted_at, limit: 6) |> Repo.all

に到達するときはspawnし終わった直後なので、ユーザが作られているのかわからないのです。手元では、usersは最初につくったExample Userさんだけになってしまいました。で、どうしたかというと、Taskですよ。

Helper.insert_user!("Example User", "example@railstutorial.org", "foobar", true)

1..99
|> Enum.map(&Task.async(Helper, :insert_user!, [Faker.Name.name, "example-#{&1}@railstutorial.org", "password"]))
|> Enum.map(&Task.await/1)

users = from(u in User, order_by: :inserted_at, limit: 6) |> Repo.all |> IO.inspect

(for _ <- 1..50, user <- users, do: user)
|> Enum.map(fn user ->
  Task.async fn ->
    user
    |> build_assoc(:microposts)
    |> Micropost.changeset(%{content: Faker.Lorem.sentence(5)})
    |> Repo.insert!
  end
end)
|> Enum.map(&Task.await/1)

ユーザを100人並列でつくって、作り終わってから6人持ってきて、50個ずつmicropostを作っています。ここまで来ると、6人作り終わった時点でmicropostを作り始めたくなりますがそれはまたあとで。

あと、ユーザが持つ50個の内容が全員一緒というのもどうなんだいということと、こっちの方が書きやすかったので、全員バラバラな内容のmicropostを作るようにしちゃいました。

テーマはFB matteをベースにしてます。作者さんに感謝を込めて。