Reputation: 2600
I have a simple supervisor module like:
defmodule Final.Users.Supervisor do
use Supervisor
def start_link, do: Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)
def init(:ok) do
children = [
worker(Final.UserServer, [], restart: :temporary)
]
supervise(children, strategy: :simple_one_for_one)
end
def create_user(id), do: Supervisor.start_child(__MODULE__, [id])
end
What I would like to do on start of application is, lookup database and call create_user/1 for every user entry in db.
I tried Process.send_after()... in init but it gives error(** (EXIT) process attempted to call itself)
Does it even make sense to try to do this in this module? Should I setup another worker(genserver) that will then query DB and call this Users.Supervisor.create_user/1 ? Example:
defmodule Final.Users.Starter do
alias Final.Repo
alias Final.Users.Supervisor, as: Sup
import Ecto.Query, only: [from: 2]
use GenServer
def start_link() do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(:ok) do
Process.send_after(self(), :started, 0)
{:ok, %{}}
end
def handle_info(:started, %{}) do
query = from(p in "users",
select: p.id)
ids = Final.Repo.all(query)
Enum.each(ids, fn(x) -> Sup.create_user(x) end)
{:noreply, %{}}
end
end
Upvotes: 0
Views: 2109
Reputation: 196
You cannot start dynamic children in the supervisor's init/1
callback as this function returns the children specification to the newly started supervisor process. In other words, the supervisor don't know how to start children before this callback returns.
Setting up a GenServer solely for doing some initialisation work seems to be too much. A better idea would be to spawn a temporary process to do the job and the quit immediately.
For this purpose you could use a Task
:
Task.start_link(fn ->
query = from(p in "users", select: p.id)
ids = Final.Repo.all(query)
Enum.each(ids, fn(x) -> Sup.create_user(x) end)
end)
Such task could be spawn from your application's main module. Note however, that if this task fails an exit signal will be sent back to the caller.
Upvotes: 4