在 Elixir 中启动同一事件处理程序的多个实例

Launching multiple instances of the same event handler in Elixir

我在 elixir 中有一个简单的事件处理程序,使用 GenEvent:

defmodule myHandler do
    use GenEvent
    #Callback
    def handle_event {:message, x}, state do
        IO.puts("Message value is #{x}")
        {:ok, [x|state]}
    end
end

我可以用通常的方式启动一个处理程序和一个管理器:

{:ok, mgr} = GenEvent.start_link

myServer.start_link(mgr)

GenEvent.add_handler(mgr,myHandler, [])

但是,我想启动一个监督树,其中有 N 个处理程序,每个处理程序都有不同的 ID,使用相同的管理器。

我试过了:

Gen.Event.add_handler({mgr, :id1},myHandler, [])

,没有运气!相反,我收到以下错误:

** (Mix) Could not start application : exited in: myApp.start(:normal, [])
** (EXIT) no connection to :id1

我是 Elixir 的新手,所以我对文档有点费劲。如果有人能告诉我怎么做,我将不胜感激!谢谢。

你总是可以在 MyHandler 中拥有更复杂的状态:

defmodule MyHandler do
  use GenEvent

  def handle_event({:message, id, message}, {id, messages}) do
    IO.puts "[ID: #{inspect id}] Message value is #{inspect message}."
    {:ok, {id, [message | messages]}}
  end

  def handle_event(_, state) do
    {:ok, state}
  end
end

要按 id 过滤消息,我会将消息结构更改为:

{:message, id, message}

如果不这样做,每个处理程序都会打印相同的消息。我猜这就是你想要 ID 的原因。

然后有一个 id,你可以这样做:

{:ok, manager} = GenEvent.start_link
MyServer.start_link manager
GenEvent.add_handler manager, MyHandler, {id, []}

如您所见,新状态是 {id :: atom, messages :: list} 而不是简单的消息列表。

那么发送消息就可以了:

GenServer.sync_notify manager, {:message, id, message}

示例:

初始化管理器:

iex(1)>  {:ok, manager} = GenEvent.start_link
{:ok, #PID<0.75.0>}

添加处理程序:

iex(2)> GenEvent.add_handler manager, MyHandler, {:id0, []}
:ok

测试 ID 为 :id0 的消息并打印消息:

iex(3)> GenEvent.sync_notify manager, {:message, :id0, "Hello"} 
[ID: :id0] Message value is "Hello".
:ok

用不存在的 ID :id1 测试一条消息,它不打印任何内容:

iex(4)> GenEvent.sync_notify manager, {:message, :id1, "Hello"}
:ok

给你。我希望这会有所帮助:)

P.S:如果你的状态太复杂,你总是可以使用map:

%{id: id, messages: []}

事实证明,要将多个处理程序添加到同一个管理器,您需要遵循以下原则:

GenEvent.add_handler(:myManager, {myHandler, :id1}, [])

我把争论搞砸了 - 感谢 Elixir slack 频道上精彩的@true_droid。