Skip to content

Events And Destinations

Ahmad Elassuty edited this page Feb 2, 2021 · 6 revisions

Events

To organise your domain events, EventRouter requires a class for each event. Those event classes must inherit from EventRouter::Event base class. For example, you can create a new OrderPlaced event like:

class OrderPlaced < EventRouter::Event; end

The EventRouter::Event base class defines some general attributes for the event:

  • uid: Randomly generated UUID per event
  • correlation_id: Randomly generated UUID
  • created_at: defaults to Time.now
  • payload: All custom event attributes

When you initialise your event, you can override any of the previous attributes and provide your event attributes:

event_1 = OrderPlaced.new(uid: 'foo', correlation_id: 'bla', attr_1: 1, attr_2: 2)
puts event.payload == { attr_1: 1, attr_2: 2 }

Event custom options

You can set custom options on the event level using event_options method that accepts a hash. The options will be available through the class and instance options method. Delivery adapters make use of those options to make routing decisions on event level.

class OrderPlaced < EventRouter::Event
  event_options queue: :orders, retry: 5
end

Destinations

Each event can have one or more destinations. Also, your destinations must have a unique name within the event. If you are using async type delivery adapter, make sure that you don't rename or remove a destination till all scheduled events are processed.

class OrderPlaced < EventRouter::Event
  deliver_to :email_notifier, handler: EmailNotifier
  deliver_to :email_notifier_2, handler: EmailNotifier, handler_method: :order_placed_2
end

Destination attributes

Define destinations using deliver_to method. deliver_to method requires at least two attributes:

  1. A unique name for the destination. It is used for internal mapping, e.g email_notifier
  2. handler attribute to define the destination class that should receive the event, e.g EmailNotifier
class OrderPlaced < EventRouter::Event
  deliver_to :email_notifier, handler: EmailNotifier
end

Destination also provide more attributes that can be configured to customise its behaviour:

handler_method

Use this option to customise the name of the handler class method. By default it is set to the event class name, snake_cased.

class OrderPlaced < EventRouter::Event
  deliver_to :email_notifier, handler: EmailNotifier, handler_method: :order_placed
end

payload_method

You can send custom payload for each destination. The payload method will be invoked before calling the handler if the event defines any. Use this option to customise the name of the payload method. By default it is set to the destination name + '_payload' suffix.

class OrderPlaced < EventRouter::Event
  deliver_to :email_notifier, handler: EmailNotifier
  deliver_to :email_notifier_2, handler: EmailNotifier, payload_method: :custom_email_notifier_payload

  def email_notifier_payload
    # [TODO] return custom payload to be sent with the event to the email_notifier destination.
  end

  def custom_email_notifier_payload
    # [TODO] return custom payload to be sent with the event to the email_notifier_2 destination.
  end
end

prefetch_payload

It is also possible to prefetch the payload incase you use async delivery adapter by enabling this option. In this case, the payload will be fetched before your worker is scheduled.

class OrderPlaced < EventRouter::Event
  deliver_to :email_notifier, handler: EmailNotifier, prefetch_payload: true
end

Destination custom options

Like events, you can pass any options to the destination and access it through options method. Delivery adapters make use of those options to make routing decisions on destination level.

class OrderPlaced < EventRouter::Event
  deliver_to :mailer, handler: Mailer, queue: :mailer, retry: false
end

Handlers

Once you have defined your domain event, you will also need to define the handler class. EventRouter will look by default for a class method with the same event name in the handler.

The handler methods should receive a single hash argument that will have two keys:

  1. The event itself
  2. The custom payload, see payload_method options
class EmailNotifier
  def self.order_placed(event:, payload:)
    # [TODO] Handle the event here
  end
end

If payload is not needed, you can discard the payload:

class EmailNotifier
  def self.order_placed(event:, **_payload)
    # [TODO] Handle the event here
  end
end

Module type Handlers

EventRouter does not put any constraints on the handler object, it can be a class as shown in the previous examples, or can be defined as module:

module EmailNotifier
  module_function

  def order_placed(event:, payload:)
    # [TODO] Handle the event here
  end
end