У меня проблема со связью с работниками, созданными в моем dynamicSupervisor.после запуска все мои работники я пытаюсь позвонить одному по pid и генерируется одна ошибка (всегда).В начале ребенка я держу пид с ец.Затем, когда я хочу позвонить этому ребенку, я получаю pid от ets по идентификатору.Все идет нормально.Проблема заключается в следующем:
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