I have a simple event handler in elixir using 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
I can start one handler and a manager in the usual way:
{:ok, mgr} = GenEvent.start_link
myServer.start_link(mgr)
GenEvent.add_handler(mgr,myHandler, [])
However, I would like to start a supervision tree where there are N handlers, each with a different id, using the same manager.
I tried:
Gen.Event.add_handler({mgr, :id1},myHandler, [])
, with no luck! In stead I get the following error:
** (Mix) Could not start application : exited in: myApp.start(:normal, [])
** (EXIT) no connection to :id1
I'm a newbie to Elixir and so am struggling with the documentation a bit. I'd be grateful if someone can show me how! Thanks.
You can always have a more complex state in 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
To filter messages by id, I would change the message structure to:
{:message, id, message}
If you don't do this, every handler will print the same message. I guess that's why you want the ID.
Then having an id
, you could do something like:
{:ok, manager} = GenEvent.start_link
MyServer.start_link manager
GenEvent.add_handler manager, MyHandler, {id, []}
As you can see the new state is {id :: atom, messages :: list}
instead of a simple list of messages.
Then its just a matter of sending the message:
GenServer.sync_notify manager, {:message, id, message}
Example:
Initialize the manager:
iex(1)> {:ok, manager} = GenEvent.start_link
{:ok, #PID<0.75.0>}
Add the handler:
iex(2)> GenEvent.add_handler manager, MyHandler, {:id0, []}
:ok
Test a message with ID :id0
and prints the message:
iex(3)> GenEvent.sync_notify manager, {:message, :id0, "Hello"}
[ID: :id0] Message value is "Hello".
:ok
Test a message with the inexistent ID :id1
and it doesn't print anything:
iex(4)> GenEvent.sync_notify manager, {:message, :id1, "Hello"}
:ok
There you go. I hope this helps :)
P.S: If your state is too complex, you can always use a map:
%{id: id, messages: []}