Commanded v0.15.0 Commanded.Event.Handler behaviour View Source

Defines the behaviour an event handler must implement and provides a convenience macro that implements the behaviour, allowing you to handle only the events you are interested in processing.

You should start your event handlers using a Supervisor to ensure they are restarted on error.

Example

defmodule AccountBalanceHandler do
  use Commanded.Event.Handler, name: __MODULE__

  def init do
    with {:ok, _pid} <- Agent.start_link(fn -> 0 end, name: __MODULE__) do
      :ok
    end
  end

  def handle(%BankAccountOpened{initial_balance: initial_balance}, _metadata) do
    Agent.update(__MODULE__, fn _ -> initial_balance end)
  end

  def current_balance do
    Agent.get(__MODULE__, fn balance -> balance end)
  end
end

Start your event handler process (or use a Supervisor):

{:ok, _handler} = AccountBalanceHandler.start_link()

Event handler name

The name you specify is used when subscribing to the event store. Therefore you should not change the name once the handler has been deployed. A new subscription will be created when you change the name, and you event handler will receive already handled events.

Subscription options

You can choose to start the event handler’s event store subscription from :origin, :current position, or an exact event number using the start_from option. The default is to use the origin so your handler will receive all events.

Use the :current position when you don’t want newly created event handlers to go through all previous events. An example would be adding an event handler to send transactional emails to an already deployed system containing many historical events.

Example

Set the start_from option (:origin, :current, or an explicit event number) when using Commanded.Event.Handler:

defmodule AccountBalanceHandler do
  use Commanded.Event.Handler,
    name: "AccountBalanceHandler",
    start_from: :origin
end

You can optionally override :start_from by passing it as option when starting your handler:

{:ok, _handler} = AccountBalanceHandler.start_link(start_from: :current)

Consistency

For each event handler you can define its consistency, as one of either :strong or :eventual.

This setting is used when dispatching commands and specifying the consistency option.

When you dispatch a command using :strong consistency, after successful command dispatch the process will block until all event handlers configured to use :strong consistency have processed the domain events created by the command. This is useful when you have a read model updated by an event handler that you wish to query for data affected by the command dispatch. With :strong consistency you are guaranteed that the read model will be up-to-date after the command has successfully dispatched. It can be safely queried for data updated by any of the events created by the command.

The default setting is :eventual consistency. Command dispatch will return immediately upon confirmation of event persistence, not waiting for any event handlers.

Example

defmodule AccountBalanceHandler do
  use Commanded.Event.Handler,
    name: "AccountBalanceHandler",
    consistency: :strong
end

Link to this section Summary

Functions

Macro as a convenience for defining an event handler

Callbacks

Event handler behaviour to handle a domain event and its metadata

Optional initialisation callback function called when the handler starts

Link to this section Types

Link to this type consistency() View Source
consistency() :: :eventual | :strong
Link to this type domain_event() View Source
domain_event() :: struct()
Link to this type metadata() View Source
metadata() :: struct()
Link to this type subscribe_from() View Source
subscribe_from() :: :origin | :current | non_neg_integer()

Link to this section Functions

Link to this macro __using__(opts) View Source (macro)

Macro as a convenience for defining an event handler.

Example

defmodule ExampleHandler do
  use Commanded.Event.Handler, name: "ExampleHandler"

def init do
  # optional initialisation
  :ok
end

def handle(%AnEvent{..}, _metadata) do
  # ... process the event
  :ok
end

Start event handler process (or configure as a worker inside a supervisor):

{:ok, handler} = ExampleHandler.start_link()

Link to this section Callbacks

Link to this callback handle(domain_event, metadata) View Source
handle(domain_event(), metadata()) ::
  :ok |
  {:error, :already_seen_event} |
  {:error, reason :: any()}

Event handler behaviour to handle a domain event and its metadata

Return :ok on success, {:error, :already_seen_event} to ack and skip the event, or {:error, reason} on failure.

Link to this callback init() View Source
init() :: :ok | {:stop, reason :: any()}

Optional initialisation callback function called when the handler starts.

Can be used to start any related processes when the event handler is started.

Return :ok on success, or {:stop, reason} to stop the handler process.