For the last few months, I’ve been writing an app that gathers social network data in real time and does some calculations to it before sending it on to a user’s browser. I decided to use Server-Sent Events (SSEs, aka EventSource), and wanted to share my learnings.
An EventSource uses HTTP streaming and keeps a connection to the server, which will continuously send an event-stream (more on those below). Communication is one-way, the client has no way to communicate back with the server through the event-stream.
Anatomy of an EventSource request
To illustrate how EventSources work, consider the scenario of a live stock ticker app. Here’s how an EventSource HTTP request and response might look:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
There are a few things to note here:
- An event is simply some lines of text with special prefixes like
- Events are terminated by multiple line feeds (
- Events may have a type or id, but it’s optional
- Comments should be sent every so often when data isn’t to keep connections alive
Example client and server code
Here’s what we might write for a web client that would consume an EventSource and update a stock chart and news ticker in real-time.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Here’s a little Sinatra server that continuously gets stock data for a given symbol. This is mostly for illustration, and I haven’t tested this stuff much, so please use it at your own risk.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Luckily, Server-Sent Events uses plain old HTTP so we can create polyfills for older browsers.
There seem to be 3 solid polyfill solutions out there to extend support for EventSource back to IE8 and up by using XHR polling as a fallback:
- Remy Sharp’s Polyfill - This is the only true polyfill here in that it has no library dependencies and uses the native EventSource implementation if it exists. Supports IE7+
- Rick Waldron’s Polyfill - A jQuery plugin with a simple API that also uses the native implementation if it’s available
- Yaffle’s Polyfill - This is the one I used because it replaces the native implementation with one that normalizes behavior cross-browser and supports CORS requests where possible
Server-Sent Events in practice
Debugging isn’t too difficult because at least Chrome Dev Tools shows every EventSource transaction in the Network tab, but it does help to be able to run both client and server yourself so you can carefully deconstruct problematic scenarios (like race conditions, perhaps).
It’s worth mentioning that all of the real-time updates to the app was actually a bad UX, and so I decided to just poll for updates and show notifications. I learned that you should consider definitely strongly consider UX before choosing a solution (or at least validate the assumption that you need real-time updates). Heroku made keeping things real-time painful because it closes connections that last over 1 minute and so I had a lot of code to keep the stream going not only to browsers but also to my MongoDB store. Just something to consider when choosing an app host.