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

时间:2015-12-18 14:06:25

标签: elixir otp gen-event

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

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的新手,所以我正在努力处理文档。如果有人能告诉我如何,我将不胜感激!感谢。

2 个答案:

答案 0 :(得分: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

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

P.S:如果您的州太复杂,您可以随时使用map

%{id: id, messages: []}

答案 1 :(得分:4)

因此,事实证明,要向同一个经理添加多个处理程序,您需要以下内容:

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

我让这个论点搞得一团糟 - 感谢Elixir懒散频道上精彩的@true_droid。