After discussing with plenty of developers during the last few months, I have realized that a huge portion of them don’t know what “Server-Sent Events” (or “SSE” or “EventSource”) is. My aim here is to give you all the information you may need about Server-Sent Events.
Server-Sent Events: Why should you even learn anything about SSE?
As the economy and your users are more and more real-time oriented, you need Server-Sent Events if displaying the last data updates to your users may change their actions. The data itself need not change often, but when it changes, you really want users to know it!
Let’s look at some cases before we explain the technical details:
– Users may click on the last news available rather than shutting down the page.
– Services/product availability. If you sell products or services rare for this specific client (car-sharing, docks for bike-sharing, promotions with limited stocks…), you want to make sure your prospect knows it is available as soon as possible.
– Prices
– Social/chat… no need to explain!
– You may just want to display rapidly changing data: game score, trading, dashboard…
“I don’t care about your “Server-Sent stuff,” I have WebSockets!”
1) It means you already understood that you need something better than HTTP Polling. Good!
2) There are pros/cons for WebSocket and SSE. I suggest you read this blog post and come back here afterward… I will be waiting for you…
If you are lazy, here is a very short summary. WebSockets are bilateral (you don’t always need bi-direction), not HTTP (some proxy won’t let it go through) “protocol” without standards for error handling. SSE is mono-directional (server to client), HTTP protocol with error handling standards. Both improve hugely latency for users. From a server load point of view, we achieved better performance with SSE than WebSockets (a higher number of final users handled by one server). Read more about AMPLIFY Streams.
“I don’t care about your “Server-Sent stuff,” I will request every half a second!”
… Now we need to explain a little more what Server-Sent Events are.
So what are Server-Sent Events?
A client subscribes to a “stream” from a server and the server will send messages (“event-stream”) to the client until the server or the client closes the stream. It is up to the server to decide when and what to send the client, for instance, as soon as data changes.
To fully understand SSE, we need to explain polling. The “historical” method of receiving information is to ask for it. The good old “request/response” paradigm! When you poll, the client-side asks for information and a server gives back the information available. No way to get something without asking it. With AJAX, you can make the polling happen with a pre-defined frequency.
(To optimize server load and bandwidth, you could decide that the server answers “No content” if the content has not changed since the last client request… but it means your API is not RESTful anymore.
Comparing polling, long-polling & SSE messages for real-time updates
Well, there are five major consequences of this ongoing polling:
– You will overcharge the server load. It is hard to make benchmarks comparing SSE and “machine-gun” polling because it is depending on the frequency of polling data itself, the server configuration, etc. When we compared different scenarios, we ended up with a factor of three to 10: one SSE server can handle three to 10 times more users than a polling server (with the same objectives of latency).
– You will overload networks with useless data because the polling will send data even if they didn’t change! This is bad for the server-side and client-side costs and terrible for the planet (this one is maybe why I am writing this blog post! Did you know the web environmental footprint is equivalent to 40 nuclear plants in energy consumption and the whole civil flight in greenhouse gas?).
Again, benchmarking polling versus streaming depends on the dataset, but we have tested it on various public APIs, and the gain varies from 20% (all data is changing often, we are just saving headers & round-trips) to 95% (small parts of the dataset is not changing not that often).
– Pushing consumes 75% to 95% less end-user battery than polling (here is the study)… don’t you want your user to keep on using your app?
– Polling requiring 3 round-trips (TCP SIN, SSL, and Data). In 3G, one round-trip takes 150 ms. So one polling will need 450 ms before the mobile receive any useful data. Once the connection is set with SSE, the mobile will receive new data in 75ms (as it directly sends data from the server to the client).
– Last but not least: you won’t be proud of your code!
TLDR: polling to display real-time data feels like this:
With Long-Polling (Hanging GET / COMET), the server will wait for a change of data before sending the response. The server will “hold” the request until it makes sense to send something. It might look attractive because you will alleviate useless responses, but it requires hacks (such as appending script tags to an “infinite” iframe) and server loads which are still huge. How do you handle “up-dates” queuing, missed messages, and disconnections?
We will first have a look at the messages themselves, then client-side implementation, and finally server-side one.
Event-stream (the cool name for Server-Sent Events messages)
The event-stream is a simple stream of text data which must be encoded using UTF-8. Messages in the event-stream are separated by a pair of newline characters (“\n”).
The following field names are defined in the specification:
Event: The event’s type. It will allow you to use the same stream for different content. A client can decide to “listen” only to one type of event or to interpret differently each event type.
Data: The data field for the message. You can put consecutive “data” lines.
ID: ID for each event-stream. Useful to track lost messages.
Retry: The time to use before the browser attempts a new connection after all connections are lost (in milliseconds). The reconnection process is automatic and is set by default at three seconds. During this reconnection process, the last ID received will be automatically sent to the server… something you would need to code by yourself with WebSockets or Long-polling.
“:” : if you start the message by a colon, it will be considered as comments
Some examples
data: hello word\n\n
data: first line\n
data: second line\n\n
id: 12345
event: newuser
data: {user name : JohnDoe}\n
data: {user name : JohnDoe2}\n\n
And yes, you can easily send JSON format without breaking the synthax! And that is a very very good news!
id: 12345
event: newuser
data: { \n
data: first name : John, \n
data: last name : Doe \n
data: }\n\n
Client-Side
Browsers
Since Server-Sent Events is a W3C standard defining a Web-based API, the client-side for the web is simple and direct.
Here is an example taken from this link. It handles the connection to the server, listening to messages, and handling of those messages.
var source = new EventSource('/stats');
source.onopen = function() {
connectionOpen(true);
};
source.onerror = function () {
connectionOpen(false);
};
source.addEventListener('connections', updateConnections, false);
source.addEventListener('requests', updateRequests, false);
source.addEventListener('uptime', updateUptime, false);
source.onmessage = function (event) {
// a message without a type was fired
};
One problem is that all browsers do not support EventSource
Source: http://caniuse.com/#search=Server-sent
So you will have to test if your user browser supports SSE
if(typeof(EventSource) !== “undefined”) {
//Yeah … SSE supported!
} else {
//wtf! Let’s make a polyfill
}
If the browser does not support SSE, you can use a Polyfill. We have tested several ones available in GitHub and have decided to use this one for our own SDKs:
For more code samples, you can check our own SDK or demos (quizz with D3.js, display of financial data)
Mobile apps
For mobile apps, there is no standard API. Things are a little more complicated, so my best option is to give links to libraries and some other blog posts detailing code samples.
Android
A simple app based on SSE on GitHub
An app using Server-sent events to get data from GitHub API
iOS
An app using Server-sent events to get data from the New York Times API.
Conclusion
We advocate the use of high standards, and we believe each individual (it includes developers) should think twice before consuming unneeded resources. When an app/website needs some data updated in real-time, and there is not a need for upward data flow, Server-Sent Events should be considered first. If you disagree, please comment on this article below and we will happily reply.
Ready to grow your business?