Why Bayeux still matters

This article was prompted by a tweet from Micheil Smith:

Why are people still using cometd when we’re seeing websockets come into most modern browsers?

To recap, CometD is the reference client/server implementation of the Bayeux protocol, which defines a messaging protocol for web clients to publish and subscribe to message channels. This lets browsers send messages to each other, and lets server-side apps push messages to the browser. It’s the protocol that Faye uses behind the scenes.

Bayeux was originally designed with the browser environment in mind, considering what tools are available there: XMLHttpRequest, JSON and JSON-P, limited connections per host. Most importantly, it was designed as a technique to hack bidirectional messaging onto a request-response network transport, i.e. HTTP.

But it also, for better or worse, defines a messaging protocol involving topic channels that is independent of the network transport being used – it could even work entirely for in-process communication without going over the wire. I don’t know the history behind this, but it turns out to solve a core problem with server-to-client messaging: adequately identifying which clients to send a message to at the network level is tricky, and topic channels provide a nice abstraction that’s separate from any networking concerns.

So why do we still need Bayeux? Well first, the most obvious and boring problem: WebSockets aren’t everywhere. Chrome and Safari have them, Firefox will have them in 4.0, Internet Explorer 9 probably won’t have them (last I heard, correct me in the comments). There are projects like Socket.IO and web-socket-js that provide cross-platform socket-style networking, so the low-level problem of bidirectional networking can be worked around. Would be nice if we didn’t need them, but that’s life.

But suppose we lived in a world sans Microsoft and we could go ahead and use WebSockets for everything. Well, then you still have a problem. Several in fact. Server-side support for the protocol is still lacking, depending on which platform you use. In Ruby, you can only really do it with the small set of async servers, and even then it has to be hacked in. Obviously Node.js fares far better, although protocol support for WebSockets is still not in core and has to be done as a library, and there are already enough different implementations to demonstrate that there are different approaches that make sense in different situations. Add to this the fact that the protocol is not yet stable and you really don’t want to expose your app to this mess.

So what happens when WebSockets are deployed in all browsers and the protocol is stable? Well you’ve still got the problem of network dropouts to handle. The server will time out connections, the client’s network connection will cut out, and you don’t want to deal with reconnection/retry problems inside your pub/sub app.

And finally, as I mentioned before, most web app code in a system like Rails is typically so far from the business end of the network connection that storing a pool of connected clients and identifying them in a useful way so you can direct messages appropriately is non-trivial to say the least. One human user of your website will use many network connections as they navigate your site, and keeping track of which messages should be sent to each client-side WebSocket becomes a really hairy problem.

So this is where Faye, CometD and their ilk really shine: they provide a very high-level messaging service that makes it dead easy for you web app to publish messages, to the right users, without caring about network transports, disconnections, connection identity and the like. WebSockets are a great piece of infrastructure, and they probably exist at just about the right level of abstraction for what they do. But personally they’re not necessarily something I want to speak to directly when writing application code.

If you’ve enjoyed this article, you might enjoy my recently published book JavaScript Testing Recipes. It’s full of simple techniques for writing modular, maintainable JavaScript apps in the browser and on the server.