DynamicSupervisor - 与工人沟通的问题
Posted
技术标签:
【中文标题】DynamicSupervisor - 与工人沟通的问题【英文标题】:DynamicSupervisor - problem with communication with the workers 【发布时间】:2019-04-25 23:56:00 【问题描述】:我与在我的 dynamicSupervisor 中创建的工作人员的沟通有问题。在启动我所有的工作人员后,我尝试通过 pid 调用一个并生成一个错误(总是)。 在孩子开始时,我用 ets 保存 pid。然后,当我想打电话给这个孩子时,我通过标识符从 ets 获取 pid。到目前为止,一切都很好。 问题是当我执行以下操作时:
GenServer.call(
pid,
:action_project, %project_id: project_id, pid: :erlang.pid_to_list(pid)
)
返回以下错误:
[error] GenServer #PID<0.606.0> terminating
** (RuntimeError) attempted to call GenServer #PID<0.606.0> but no handle_call/3 clause was provided
(backercamp) lib/gen_server.ex:693: MyApplication.ProjectWorker.handle_call/3
(stdlib) gen_server.erl:661: :gen_server.try_handle_call/4
(stdlib) gen_server.erl:690: :gen_server.handle_msg/6
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message (from #PID<0.680.0>): :action_project, %pid: '<0.606.0>', project_id: "23"
State: %pid: '<0.606.0>', project_id: "23"
Client #PID<0.680.0> is alive
(stdlib) gen.erl:169: :gen.do_call/4
(elixir) lib/gen_server.ex:921: GenServer.call/3
这个电话有什么问题?
DynamicSupervisor 代码:
defmodule MyApplication.Supervisor do
use DynamicSupervisor
alias MyApplication.Management
def start_link(arg) do
DynamicSupervisor.start_link(__MODULE__, arg, name: __MODULE__)
end
def init(arg) do
DynamicSupervisor.init(arg)
end
def start_project_worker(project_id) do
spec = MyApplication.ProjectWorker, %project_id: project_id
DynamicSupervisor.start_child(__MODULE__, spec)
end
def start_all_project_workers() do
Enum.each(Management.list_all_projects(), fn %id: project_id ->
IO.puts("Started for project Id [#project_id]")
# 1s between workers
:timer.sleep(1000)
start_project_worker("#project_id")
end)
end
def action_project(pid, project_id) do
GenServer.call(
pid,
:action_project, %project_id: project_id, pid: :erlang.pid_to_list(pid)
)
end
end
工人代码:
defmodule MyApplication.ProjectWorker do
use GenServer, restart: :transient
alias MyApplication.Settings
alias MyApplication.Management
def start_link(state) do
GenServer.start_link(__MODULE__, state)
end
def init(state) do
schedule_action_project(Settings.get_frequency_ms())
state = Map.put(state, :pid, :erlang.pid_to_list(self()))
persist_state(state)
:ok, state
end
def handle_info(:schedule_action_project, %project_id: _project_id, pid: _pid = state) do
action_by_state(state)
:noreply, state
end
def handle_call(:action_project, %project_id: _project_id, pid: _pid = state) do
case action_by_state(state) do
true ->
terminate(state)
false ->
:reply, state, state
end
end
defp persist_state(state) do
IO.puts(" :: Add project_id [#state.project_id] and pid #state.pid")
:ets.insert_new(:project_backup, state.project_id, state.pid)
end
defp delete_persist_state(project_id) do
IO.puts(" :: Delete project_id [#project_id]")
:ets.delete(:project_backup, project_id)
end
defp schedule_action_project(time) do
IO.puts(" :: Schedule_action_project [#time]")
Process.send_after(self(), :schedule_action_project, time)
end
defp terminate(%project_id: project_id, pid: _pid = state) do
IO.puts(
" :: Stop processed, everything is done! project_id [#state.project_id] and pid #
state.pid
"
)
delete_persist_state(project_id)
:stop, :normal, state
end
defp action_by_state(%project_id: _project_id, pid: _pid = state) do
action_by_project(Management.get_project!(state.project_id))
end
defp action_by_project(%Project = project) do
#do something in project
end
end
【问题讨论】:
你得到什么错误?在此处发布堆栈跟踪。 【参考方案1】:问题出在处理程序中。你把所有的论点都搞砸了。 state
是GenServer
的内部状态,你不通过它,你在回调中接收它。如果您的状态是具有键 project_id
和 pid
的映射并且您将其称为 GenServer.call(pid, :action_project)
,则以下签名将匹配。
def handle_call(:action_project, %project_id: _project_id, pid: _pid = state)
您应该更改此处理程序以匹配您的调用者:
def handle_call(
:action_project, %project_id: _project_id, pid: _pid,
_from,
state
)
还要注意handle_call
回调接收三个参数(不像handle_cast
,第二个是消息的来源。
旁注: handle_info
回调也有错误的签名。
【讨论】:
哦,你是一台机器 :D 你对 handle_call 的关系是对的……handle_info 有什么问题? 我猜也一样。我不确定状态是什么。 另一个疑问。是否有可能在孩子开始时就知道它是否来自重新启动?或者有不同的孩子的初始化功能? 我不确定我是否遵循。如果您需要不同的init
,最简单的方法是创建另一个模块。
不。作为一种解决方法,您可能会在第一次启动时向 DETS 设置一个标志,从 init
检查此标志并采取相应的行为。以上是关于DynamicSupervisor - 与工人沟通的问题的主要内容,如果未能解决你的问题,请参考以下文章