Good Use Case for Server-Sent Events

September 2, 2012

Although some would say there are two competing standards for handling live events on the web, websockets and server-sent events (event source), they are really very different from each other with their own use cases. I have always been a proponent of websockets as it is bi-directional and as a result more powerful. Although in reality, there are few cases where you truly need bi-directional support. Nonetheless, I’ve always been of the opinion of “what if” one day you need bi-directional support. It’s better to be on a platform today that supports it tomorrow. As a result, I’ve never had a good use case for server-sent events. Today, I came across one.


Server sent events are actually quite easy to implement, much more so than websockets (talking pure protocol of course as frameworks exist for both that make it easy). In fact, event source at the server side is basically a standard HTTP request/response with a specific format over a long-held request. On the client-side, the browser has a built-in JavaScript API that knows how to handle that format to receive asynchronous callbacks. This allows applications to easily support server-sent events for certain use cases. My specific use case I built into a standard Servlet on Tomcat with the native JavaScript API.

So what is my use case? My use case is basically providing progress for long running tasks. Imagine a user clicks on a submit button or a link that results in a long running request. How do you notify the user of that progress? The old way was just putting a spinner on the page to notify the user that “something” was happening. However, what if the “something” actually failed or is stuck? The user would never know. The next method was the application would spin off a second AJAX request to constantly ping the server for progress. I have never been a big support of this method as it results in two connections per user as well as constantly pinging the server wasting bandwidth. Long polling came around to help alleviate the bandwidth issues, but you would still need 2 connections not to mention the expense of tearing down and bringing up the long polling connections. My answer to this is server-sent events. This could also be done with web-sockets, but it’d be much more complex and have no added benefit. Remember the principle rule of development: KISS (keep it simple). In other words, do not use complicated technology unless you get a better bang for your buck. In this scenario we already have to invoke an HTTP request to handle the submission and since SSE is essentially an HTTP request, it works nicely.

Let’s get to the code. The first portion is the server side. This example is a pure Java Servlet but you could use any technology. You could also use other servlet-based frameworks rather than dealing specifically with the servlet. This is only meant to demonstrate what you could do.

Basically, once the doGet method is called, it sets the content type and encoding so that the client knows that a EventSource connection is being established. Failure to set these settings will cause the client to error. Next, it creates a long running task to do whatever it needs to do which also has a progress state. The task is used to send another SSE whenever the progress updates. This allows the task to immediately notify the client whenever its progress updates. The actual data is sent down as JSON so that the client can parse it for information.

The client code is just as simple.

Basically, whenever the link is invoked, it sends an EventSource connection to the above servlet. Every time a message is sent it updates the progress bar accordingly. Once the complete message is received it properly closes the connection so that it is not re-established by the browser. At this point, the script would update the page notifying the user of completion.

Note that the CSS3 progress bar in this example is based off the great work at http://www.catswhocode.com/blog/how-to-create-a-kick-ass-css3-progress-bar.

The full example is at this Gist: https://gist.github.com/3604120

Comments are closed.