Запуск нескольких экземпляров одного и того же обработчика событий в 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 обработчиков, каждый с разным идентификатором, используя тот же менеджер.

Я старался:

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

без везения! Вместо этого я получаю следующую ошибку:

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

Я новичок в Elixir и поэтому немного борюсь с документацией. Буду признателен, если кто-нибудь покажет мне как! Благодарю.

2 ответа

Решение

Вы всегда можете иметь более сложное состояние в 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

Чтобы отфильтровать сообщения по идентификатору, я бы изменил структуру сообщения на:

{:message, id, message}

Если вы этого не сделаете, каждый обработчик напечатает одно и то же сообщение. Я думаю, именно поэтому вы хотите, чтобы удостоверение личности.

Тогда имея 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

Протестируйте сообщение с идентификатором :id0 и печатает сообщение:

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

Протестируйте сообщение с несуществующим идентификатором :id1 и это ничего не печатает:

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

Вот и ты. Надеюсь, это поможет:)

PS: Если ваше состояние слишком сложное, вы всегда можете использовать карту:

%{id: id, messages: []}

Так что получается, что для добавления нескольких обработчиков в один и тот же менеджер вам нужно что-то вроде:

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

У меня был весь спор - благодаря замечательному @true_droid на слабом канале Elixir.

Другие вопросы по тегам