首页 > 解决方案 > Elixir 的 GenServer 的 handle_call、handle_info、handle_cast 未被调用

问题描述

我已经实现了一个简单的Application->DynamicSupervisor系统,它在启动时Application创建一个DynamicSupervisor,然后向它发送一条消息以开始一些工作。问题是没有任何消息(通过 GenServer's cast, Kernel's send)实际上被捕获。试图GenServer.call()抛出以下错误

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

标签: elixirerlang-otp

解决方案


DynamicSupervisor行为的自定义实现GenServer

它唯一可覆盖的功能是child_spec/1.

casts虽然被有效地忽略了。当您投射消息或发送信息时,当进程无法处理它(或者即使它不存在)时,VM 会简单地忽略它。call/3是同步的,因此发送者期望回复,这就是您看到它引发的原因.

试试看GenServer.cast pid, :foo,你会收到:ok回信,因为这些消息是不承诺送达的。


推荐阅读