我正在尝试为调度程序应用程序设置监督树(请注意使用Elixir 1.5语法)。应用程序应该工作,以便:
start_child
回调动态添加子项。这将采用用于构建调度状态的初始化args。如果我没有传递任何参数,我可以使其工作 - 创建的计划表未注册,我必须在创建后修改状态。一旦我尝试添加参数,系统就会出错 - 我知道这只是我的语法误解,但我不能为我的生活弄清楚我做错了什么。我还没有发现这里的文档非常有用,我尝试过复制和修改来自GH,GH Gists和在线文章的例子,但我无法让它工作。
当前设置 - 理想情况下,我希望将id
,period
和targets
作为start_child
的参数传递,但是甚至无法将其与单个参数,所以只要坚持一个,直到我能让它运行:
申请表:
defmodule Assay.Application do
use Application
def start(_type, _args) do
children = [
{Assay.SchedulerSupervisor, []},
{Registry, keys: :unique, name: Assay.Scheduler.Registry}
]
opts = [strategy: :one_for_all, name: Assay.Supervisor]
Supervisor.start_link(children, opts)
end
end
主管:
defmodule Assay.SchedulerSupervisor do
use Supervisor
@name Assay.SchedulerSupervisor
def start_link(_args) do
Supervisor.start_link(__MODULE__, :ok, name: @name)
end
def start_schedule(id) do
Supervisor.start_child(@name, [id])
end
def init(_) do
Supervisor.init([Assay.Scheduler], [strategy: :simple_one_for_one, name: @name])
end
end
GenServer(仅显示相关的初始化函数)
defmodule Assay.Scheduler do
use GenServer
alias Assay.Scheduler
require Logger
defstruct targets: [], period: 60_000, id: nil, active: false
def start_link(id) do
GenServer.start_link(__MODULE__, [id], [name: via_tuple(id)])
end
def init([id]) do
Logger.info "starting a new #{__MODULE__} with id #{id}"
{:ok, %Scheduler{id: id}}
end
end
编辑:实际错误可能会有所帮助 - 我可以看到args是错误的,我无法弄清楚原因:
{:error,
{:EXIT,
{:undef,
[{Assay.Scheduler, :start_link, [[], 1], []},
{:supervisor, :do_start_child_i, 3, [file: 'supervisor.erl', line: 381]},
{:supervisor, :handle_call, 3, [file: 'supervisor.erl', line: 406]},
{:gen_server, :try_handle_call, 4, [file: 'gen_server.erl', line: 636]},
{:gen_server, :handle_msg, 6, [file: 'gen_server.erl', line: 665]},
{:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 247]}]}}}
答案 0 :(得分:4)
对于:simple_one_for_one
主管,Supervisor.start_child
使用子规范中指定的参数调用start函数,并使用赋予它的参数。使用Supervisor.init
时,子规范取自Elixir 1.5中模块的child_spec/1
函数。由于您使用GenServer
而没有指定自定义启动功能而[]
已传递给child_spec/1
,因此defaults to [[]]
表示您的功能已结束如果[]
为1
并且您得到未定义的函数错误,则使用两个参数id
和1
进行调用。
您可以通过明确表示您不希望GenServer通过更改
为child_spec
中的启动功能提供任何参数来解决此问题。
use GenServer
到
use GenServer, start: {__MODULE__, :start_link, []}
现在正确调用该函数,只有一个参数,即id
。
IO.inspect Assay.SchedulerSupervisor.start_link []
IO.inspect Assay.SchedulerSupervisor.start_schedule 12
将打印:
{:ok, #PID<0.82.0>}
[info] starting a new Elixir.Assay.Scheduler with id 12
{:ok, #PID<0.83.0>}