exploration with elixir GenEvent handlers
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
config
lib
test
.gitignore
README.md
mix.exs

README.md

Elixir GenEvent Testing

This project is used to show three methods of adding event handlers to a GenEvent manager.

  1. use add_handler:
  • this adds a handler to the GenEvent manager, but does not do any supervision and is not fault tolerant
  1. use add_mon_handler without handling exits:
  • this adds a monitored handler to the GenEvent manager, but does not explicitly handle :gen_event_EXIT messages. instead it relies on crashing the server its in so that it can be restarted by its supervisor
  1. user add_mon_handler handle exits:
  • this adds a monitored handler to the GenEvent manager, and explicitly handles exits. reading the event handler for any reason that is not :normal or :shutdown

In addition to the three handlers there are also two supervisors. One supervisor manages the three handlers with a :one_for_one strategy. The other manages the GenEvent manager and the handlers supervisor with a :one_for_all strategy. This ensures the handlers are re-added if the manager crashes for any reason.

Generic Event Handler used in module

defmodule EventHandler do
  use GenEvent
  require Logger

  def init(parent) do
    {:ok, parent}
  end

  def handle_event({:log, msg}, parent) do
    "handled log: #{inspect msg} in #{__MODULE__}"
    |> Logger.info

    {:ok, parent}
  end

  def handle_event({:crash, _}, parent) do
    "crash event handler #{__MODULE__}"
    |> Logger.info

    1 = 2
  end

  def handle_event(event, parent) do
    "handled event: #{inspect event} in #{__MODULE__}"
    |> Logger.info

    {:ok, parent}
  end
end

Pattern 1 - basic event handler with no monitoring

defmodule EventHandlerServer do
  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, []);
  end

  def init([opts]) do
    GenEvent.add_handler(opts.manager_name, EventHandler, self())

    {:ok, opts}
  end
end

Pattern 2 - monitored event handler

defmodule EventHandlerServer do
  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts,[]);
  end

  def init([opts]) do
    :ok = GenEvent.add_mon_handler(opts.manager_name, EventHandler, self())

    {:ok, opts}
  end
end

Pattern 3 - monitored event handler, restarts handler on exit

defmodule EventHandlerServer do
  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts,[]);
  end

  def init([opts]) do
    start_handler(opts)
    {:ok, opts}
  end

  def start_handler(opts) do
    :ok = GenEvent.add_mon_handler(opts.manager_name, EventHandler, self())
  end

  def handle_info({:gen_event_EXIT, handler, reason}, state)
    when reason in [:normal, :shutdown] do
    {:stop, reason, state}
  end

  def handle_info({:gen_event_EXIT, handler, reason}, state) do
    start_handler(state)

    {:noreply, state}
  end
end