Routing and handlers

Handlers

A handler is a piece of code that does something with a message. There is no module or superclass that you need to use to implement a handler. All that is needed is something that responds to .call with one argument, the message.

The following class can serve as a typical handler:

class NotifyCompetingBidders
  def self.call(bid_placed)
    other_bidders.each { |bidder| SendOutbidNotice.call(recipient: bidder) }
  end
end

But a handler can also be a plain block in a route:

class HandleBiddingEvents
  include Messaging::Routing

  def self.call(message)
    new.handle(message)
  end

  # A block used as a handler
  on BidPlaced do |bid_placed|
    log_bid_event bid_placed
  end
end

Routing

There are multiple ways to route messages to handlers.

Synchronous handlers

Use the call: keyword in a route to make the handler synchronous.

Messaging.routes.draw do
  on Events::BidPlaced, call: NotifyCompetingBidders
end

Be aware! The handler would trigger in the same thread as the code that publishes the event. This may or may not be a problem. But think twice before using synchronous handlers.

Enqueued handlers

Use the enqueue: keyword to make a handler be called by a background worker like Sidekiq.

Messaging.routes.draw do
  on Events::BidPlaced, enqueue: NotifyCompetingBidders
end

Be aware! Sidekiq / Resque / ActiveJob does not guarantee that the jobs will be processed in any specific order. If the order in which handlers gets called is important you should probably use a Consumer instead