Eventwire is a generic and simple interface to various backends to help building event-driven systems
Switch branches/tags
Nothing to show
Clone or download
Pull request Compare This branch is 29 commits behind cavalle:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Eventwire: Event Collaboration for the Masses Build Status

Eventwire is a generic and simple interface to various backends (AMQP, Redis, ZeroMQ, MongoDB) to help building event-driven systems

WARNING: This gem is in a very early stage of development. No first version has been released yet. That means that some of things described in this file might not be implemented, and those which are, might not be production ready.

What is Event Collaboration?

When we have components that collaborate with each other, whether they be as small objects in a single address space or as large as application communicating across the Internet, we commonly think of their style of collaboration as being driven by requests. One component needs information that another has, so the needier component requests it, if then that component needs another to do something, out goes another request.

Event Collaboration works differently. Instead of components making requests when they need something, components raise events when things change. Other components then listen to events and react appropriately. Event Collaboration leads to some very different ways of thinking about how parts need to think about their interaction with other parts.

See the complete Martin Fowler's article for a comprehensive explanation.

For example, a Project Management System might publish events when tasks are marked as completed, like this:

class Task
  include Eventwire::Publisher

  def mark_as_complete!(user)
    @completed = true
    publish_event :task_completed, :task_name => @name, :by => user.name
  # ...

Meanwhile, on the other side of the universe, an Analytics Application is supposed to gather data to calculate the average task completion time. Using Event Collaboration, it could be done like this:

module TasksStats
  include Eventwire::Subscriber

  on :task_created do |event|
    @start_times[event.task_name] = Time.now

  on :task_completed do |event|
    @completion_time_sum   += Time.now - @start_times.delete(event.task_name)
    @completion_time_count += 1

  def self.average_completion_time
    @completion_time_sum / @completion_time_count
  # ...

Finally, the Notifier is also interested in the same event:

class Notifier
  include Eventwire::Subscriber
  on :task_completed do |event|
    Notifier.new(:email   => find_boss_email(event.by), 
                 :subject => "Task #{event.task_name} completed").send!
  # ...

The beauty behind all this is that, using the right infrastructure, any of these components might belong to completely different applications and run in separated processes or machines. Or they all might be part of the same app and run in the same process. Components don't care about any of that, that's to say, they are very loosely coupled.

The great strength of Event Collaboration is that it affords a very loose coupling between its components; this, of course, is also its great weakness.

Be sure to check all the trade-offs in Fowler's article (“When to use it” section)

So, What's Eventwire?

Eventwire is a Ruby library that abstracts developers from the low-level details (messaging, routing, serialization…) that enable Event Collaboration.


It provides two modules, Eventwire::Publisher and Eventwire::Subscriber, which are all developers need to care about:

  • Notify changes with Eventwire::Publisher#publish_event
  • React to changes with Eventwire::Subscriber#on

See the code examples above.


Committing to that simple generic interface, Eventwire includes various drivers for different backends. Developers can choose which one to use depending on what is available in their current infrastructure or what are their needs in terms of reliability, performance or scalability. Currently four drivers are provided:

  • Eventwire::Driver::InProcess (for testing and development mainly)
  • Eventwire::Driver::AMQP (default driver. Requires an AMQP server like RabbitMQ)
  • Eventwire::Driver::Redis (experimental. Requires a Redis server)
  • Eventwire::Driver::Zero (experimental. Uses ØMQ)
  • Eventwire::Driver::Mongo (experimental. Requires a MongoDB server)


Finally, Eventwire includes a convenient Rake task for starting workers that will run the event handling logic. Eventwire's workers can be distributed between multiple machines and handle failure gracefully, so that no event is lost and any error can easily be traced. They also maximize throughput, minimize latency and fairly distribute the workload (different trade-offs might apply depending on the specific driver used. Check the drivers' docs for more info)

Getting started

Since this is 2011, I suppose your app will have a Gemfile where you have to add the gem.

gem 'eventwire'

And then install it…

$ bundler install

Now you can just include the Eventwire::Publisher and Eventwire::Subscriber wherever you want to notify or react to events as in the examples at the beginning of this document.

Eventwire's default (and recommended) driver uses an AMQP server as backend. RabbitMQ is suggested, you can install it:

In MacOSX, using Homebrew:

$ brew install rabbitmq

In Ubuntu >= 9.04:

$ sudo apt-get install rabbitmq-server

For other systems, check this.

Before running your app or your workers you need to start the server.

$ rabbitmq-server

Now, if you're not in Rails 3, add this to your Rakefile

require 'eventwire/tasks'

Finally, start a worker with:

$ rake eventwire:work

Note one important thing: By default, Eventwire won't know about your application's environment. That is, it won't be able to find and run your event handlers. That means that you need to make sure that your environment and any class including Eventwire::Subscriber are loaded before the eventwire:work task is executed.

For instance, in Rails you could add a file in config/initializers called event_handlers.rb that requires any event handler in your app (i.e. any class or module using Eventwire::Subscriber). Then, you just need to start your workers with:

$ rake environment eventwire:work


Copyright © 2011 Luismi Cavallé, released under the MIT license