4

我在 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 的新手,所以在文档方面有点挣扎。如果有人能告诉我怎么做,我将不胜感激!谢谢。

4

2 回答 2

4

你总是可以有一个更复杂的状态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

你去吧。我希望这有帮助 :)

PS:如果您的状态太复杂,您可以随时使用地图

%{id: id, messages: []}
于 2015-12-18T15:58:44.573 回答
4

所以事实证明,要将多个处理程序添加到同一个管理器,您需要以下内容:

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

我把争论搞砸了——多亏了 Elixir slack 频道上精彩的 @true_droid。

于 2015-12-18T17:13:55.210 回答