Elixir 的 GenServer handle_call、handle_info、handle_cast 未被调用
Elixir's GenServer handle_call, handle_info, handle_cast not being invoked
我实现了一个简单的 Application
-> DynamicSupervisor
系统,其中 Application
在启动时创建一个 DynamicSupervisor
,然后向它发送消息以启动一些工作。问题是 none 的消息(通过 GenServer 的 cast
,内核的 send
)实际上被捕获了。尝试 GenServer.call()
会抛出以下错误
no function clause matching in DynamicSupervisor.handle_call/3
这很奇怪,因为我已经实现了它(按照那个规范)。我确定 DynamicSupervisor
模块已启动并且不会在启动时退出。
应用模块代码:
defmodule Simulacra.Application do
use Application
def start(_type, _args) do
children = [
Simulacra.MainSupervisor
]
opts = [strategy: :one_for_one, name: Simulacra.Supervisor]
{:ok, pid} = Supervisor.start_link(children, opts)
start_supervisors(Supervisor.which_children(pid))
{:ok, pid}
end
defp start_supervisors([h|_t] = list) when is_list(list) do
{_, pid, _, _} = h
start_supervisors(pid)
end
defp start_supervisors([]) do
#noop
IO.puts "Something"
end
defp start_supervisors(pid) do
GenServer.cast(pid, :start)
send(pid, :ping)
GenServer.call(pid, :ping) <-- Throws an error
end
end
主管代码:
defmodule Simulacra.MainSupervisor do
@moduledoc false
use DynamicSupervisor
def start_link([]) do
DynamicSupervisor.start_link(__MODULE__, [], name: __MODULE__)
end
def init(_noop) do
DynamicSupervisor.init(strategy: :one_for_one)
end
def handle_info(:ping, state) do
IO.puts "sth"
end
def handle_cast(:start, state) do
# do_something
{:noreply, state}
end
def handle_call(:ping, _from, _x) do
{:reply, "bing", "bong"}
end
DynamicSupervisor
是 GenServer
behaviour.
的自定义 实现
它唯一可覆盖的功能是child_spec/1
。
您的 casts
虽然实际上被忽略了。当您发送消息或发送信息时,VM 会在进程无法处理它(或者即使它不存在)时简单地忽略它。call/3
是同步的,因此发件人期望回复,即为什么你看到它加注。
试试 GenServer.cast pid, :foo
,你会收到 :ok
回信,因为这些消息未被承诺送达。
我实现了一个简单的 Application
-> DynamicSupervisor
系统,其中 Application
在启动时创建一个 DynamicSupervisor
,然后向它发送消息以启动一些工作。问题是 none 的消息(通过 GenServer 的 cast
,内核的 send
)实际上被捕获了。尝试 GenServer.call()
会抛出以下错误
no function clause matching in DynamicSupervisor.handle_call/3
这很奇怪,因为我已经实现了它(按照那个规范)。我确定 DynamicSupervisor
模块已启动并且不会在启动时退出。
应用模块代码:
defmodule Simulacra.Application do
use Application
def start(_type, _args) do
children = [
Simulacra.MainSupervisor
]
opts = [strategy: :one_for_one, name: Simulacra.Supervisor]
{:ok, pid} = Supervisor.start_link(children, opts)
start_supervisors(Supervisor.which_children(pid))
{:ok, pid}
end
defp start_supervisors([h|_t] = list) when is_list(list) do
{_, pid, _, _} = h
start_supervisors(pid)
end
defp start_supervisors([]) do
#noop
IO.puts "Something"
end
defp start_supervisors(pid) do
GenServer.cast(pid, :start)
send(pid, :ping)
GenServer.call(pid, :ping) <-- Throws an error
end
end
主管代码:
defmodule Simulacra.MainSupervisor do
@moduledoc false
use DynamicSupervisor
def start_link([]) do
DynamicSupervisor.start_link(__MODULE__, [], name: __MODULE__)
end
def init(_noop) do
DynamicSupervisor.init(strategy: :one_for_one)
end
def handle_info(:ping, state) do
IO.puts "sth"
end
def handle_cast(:start, state) do
# do_something
{:noreply, state}
end
def handle_call(:ping, _from, _x) do
{:reply, "bing", "bong"}
end
DynamicSupervisor
是 GenServer
behaviour.
它唯一可覆盖的功能是child_spec/1
。
您的 casts
虽然实际上被忽略了。当您发送消息或发送信息时,VM 会在进程无法处理它(或者即使它不存在)时简单地忽略它。call/3
是同步的,因此发件人期望回复,即为什么你看到它加注。
试试 GenServer.cast pid, :foo
,你会收到 :ok
回信,因为这些消息未被承诺送达。