我有一个简单的管理员模块,如:
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
我想在开始应用程序时做的是查找数据库并为db中的每个用户条目调用create_user / 1.
我在init中尝试了Process.send_after()...但是它给出了错误(**(EXIT)进程试图调用自己)
尝试在此模块中执行此操作是否有意义?我应该设置另一个工作人员(genserver)然后查询DB并调用此Users.Supervisor.create_user / 1?例如:
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
答案 0 :(得分:3)
您无法在主管的init/1
回调中启动动态子项,因为此函数会将子规范返回给新启动的主管进程。换句话说,在此回调返回之前,主管不知道如何启动子项。
仅仅为了进行一些初始化工作而设置GenServer似乎太多了。更好的想法是产生一个临时过程来完成工作并立即退出。
为此,您可以使用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)
此类任务可以从应用程序的主模块中生成。但请注意,如果此任务失败,退出信号将被发送回呼叫者。