Faye 0.6: it’s all about clustering

After a longer-than-I-would-have-liked gestation period that began around six months ago, Faye 0.6 is finally out. The major feature in this release is the introduction of ‘engines’, a mechanism that gives us a great deal of freedom about how the back-end is implemented, and lets us do useful things like clustering the HTTP front-end.

In previous releases, the Bayeux protocol and the pub/sub logic backing it up were part of the same class, Faye.Server. All the application state – clients and their subscriptions – was stored in memory by this class. In the new release, the protocol layer and the core pub/sub logic have been separated – the protocol still lives in Faye.Server but the messaging logic has been factored out into several classes called ‘engines’. This means we can change how the message distribution layer is implemented without affecting the protocol.

The first big advantage of this is that we can write engines that store state in an external service, meaning we can distribute a single Faye service across many web servers if connection volume becomes a problem. The new Redis engine does just that:

var bayeux = new Faye.NodeAdapter({
  mount:   '/bayeux',
  timeout: 60,
  engine:  {
    type: 'redis',
    host: 'localhost',
    port: 6379
  }
});

You can start up a cluster of Faye web servers that all connect to the same Redis database, and clients can connect to any one of these web servers to interact with the service. The default engine is an in-memory one, so your existing code will continue to store state in memory. The in-memory engine has lower latency because it doesn’t perform external I/O, but obviously it cannot be clustered.

This engine system also opens up the possibility to turn Faye into a web front-end for whatever messaging technology you use internally. Because all the protocol validation is handled higher up the stack, the engines themselves are very small classes. Here are the in-memory and Redis engines, and the unit tests that are run against both:

So you can see it’s not a lot of work to implement a new engine and register it. Once you’ve called

Faye.Engine.register('my-engine', MyEngine)

you can use it by setting engine.type when creating your NodeAdapter.

The only API change resulting from this is that it’s no longer possible to publish on wildcard channels like /foo/*. Other Bayeux servers prohibit this already but previous versions of Faye allowed it. In order to keep the engines simple and fast I’ve decided to remove this feature. Subscribing to wildcard channels is still supported.

The other major change in this release comes from Matthijs Langenberg, who’s added a CORS transport to the client. This will now be used instead of the JSON-P transport for cross-domain communication in browsers that do not support WebSockets. It will particularly help in Firefox, which shipped without WebSocket in version 4.0 and guarantees execution order of injected scripts. This meant the long-polling JSON-P request from Faye would block calls made to other APIs like Google Maps, making UIs unresponsive. This should now be a thing of the past.

Finally I just want to thank Martyn Loughran, whose em-hiredis powers the Ruby Redis engine in Faye. Martyn works on Pusher, a really polished hosted push service that uses Redis internally, and it’s really nice of them to open-source their client for others to use. I tried three other Redis clients in Ruby and none of them do pub/sub as nicely as em-hiredis.

As usual, install through gem or npm and hop on the mailing list if you have any problems. I’m on holiday at the moment but I’ll get onto your feedback when I’m home next week.