Years ago I was developing mission-critical applications that required updates based on incoming real-time events. At that time I was obsessed with the notion of an Enterprise Service Bus (ESB) and Service Oriented Architecture. It all looked so cool; you create small atomic services and have them process incoming events and exchange messages with each other and the client.
There was one problem.
In the era of Web applications, I could not figure out a really good way to send the messages back to the browser. Of course there was the obvious solution: create a facade WebService and call it repeatedly from the browser in a request-response manner while using the ESB to orchestrate all that on the server side.
But that just did not sound cool in an ‘events-driven world’. For starters, what if there were no events? Do I just keep calling just to get nothing back? That seemed wasteful. Secondly, services ‘orchestration’ works really well when there is an event to process. It does not necessarily work well when you are calling it every 100 ms just to retrieve an event and start its processing. That’s a lot of latency in my architecture that I wanted to avoid. Anyway, the whole deal was kinda falling apart.
Later I moved to developing more typical business applications using REST APIs with jQuery, AngularJS and similar frameworks. It all seemed to work rather well.
Then one day, I had an issue with one of my apps. I needed to update different parts of the page (and quite a few of them) to reflect different changes happening in the system (results of long operations, other users activities, etc). Creating one ‘big’ REST call to capture all the changes did not sound like a good idea. Our team decided it was better to create a REST call for every possible type of update.
For a while it worked. Unfortunately we soon found ourselves with 100+ timers and REST calls going on at the same time. Performance of the page decreased dramatically and maintenance became a huge nightmare.
At that time somebody mentioned “WebSockets”.
One would expect me to say that we started using them. We did not. Why? Mostly because we had no idea what they were. I looked online, found a nice Wikipedia article (great source of information – yeah right, don’t get me started) and thought “Wow! WebSockets are a great thing for event-driven systems that I used to work on. The next time I need to develop a stock market streaming app with real-time positions updates or something similar I will use it!”. And I had tremendous misconceptions about WebSockets.
- I thought that not all browsers support them since it is something new.
Wrong!!! The WebSocket protocol and standard APIs are very mature. Both the IETF and W3C have formally standardized WebSockets since 2011 and is fully supported by all modern browsers!
- I thought that the learning curve will be too steep and we plainly did not have time to deal with it.
Wrong again!!! With client libraries that are provided by the WebSockets vendor it takes very little time (an hour or less) to get familiar with the technology and start developing an application.
- I thought that we will have to rewrite our all great REST beauty entirely to accommodate WebSockets
Wrong #3! All it takes, is to move the very same code from $http(…).then() (for AngularJS) or $.ajax(…).then() callback function into the callback function that is called when the WebSocket message is received.
Later I was asked by a friend of mine to play with the Kaazing WebSocket Gateway (I was not working for Kaazing at that time). I tried to pick the most ‘trivial’ app (that was not domain specific such as data streaming, gaming, etc.) and decided on a good-old TODO list. Except, mine had to be shared between multiple users.
Even with such a simple app I immediately realized the benefits that WebSockets offered comparing to doing it with REST calls.
If we were to implement shared TODO using REST we would at least have to deal with several issues:
- Server Load. A shared TODO application with REST clients has to continuously query the server for the changes. Needless to say these REST calls impact overall performance regardless if anything has changed, or not. If I had 100,000 clients, that means 100,000 calls to the server and database, etc.
- Server Logic to Detect Changes. Clearly we do not want to send the whole list of TODO items to everyone. There is a need to implement the logic to detect changes and notify interested client apps about these changes. Not too trivial.
- Race conditions. REST implementations will require timers to go off rather often to address the situation when multiple users are updating the same record. Ideally, I would want to disable the record for everyone else once some user is working on it. Using REST could potentially result in a seriously high load on both the servers and the clients. And the browser may not be fond of the JavaScript code that issues the REST call every 100 or so ms. Server will get less and less happy as more and more clients get on board. Think of the extreme case: 100,000 clients @ 100 ms each = 1,000,000 calls/sec. which may, by the way, simply inform that no changes occurred!
Then the lightbulb went off. Using WebSockets addresses all of these concerns!
- Servers load is not an issue anymore. Performance is now based on the number of changes but not on the number of the clients. As the change occurs, all the interested clients are notified. The rest of the time, nothing is happening. There is no wasted computing resources.
- There is no need of any server logic to track the changes at all! Once the user changed the TODO item, a message is sent to all the interested clients to simply update their UI. We did have to also have another listener on the server to update the database with the changes. But the database is not overloaded at all. It just has to work a little bit just for the initial load to get the state for the new coming clients.
- With a high-throughput gateway (such as Kaazing), clients can easily send messages when the user’s mouse hovers over a certain item (either in or out). Other clients that are not interested in these events can merely just disable their interest. Certainly it would be incorrect to say that race conditions will never happen, but the possibility is far more remote.
The sample app I created resulted in a tutorial.
I also learned a critical fact that somehow I missed in that earlier Wikipedia article. WebSocket can be and should be used as a low-level transport layer to allow any applications protocol such as the publish/subscribe model (e.g., JMS, AMQP or some custom protocol) to run over the web. While it may not sound too exciting for front-end developers it, actually, opens a whole world of features that enterprise developers have been successfully using for years.
Now that I’ve laid to rest my initial misconceptions about WebSocket and had my “Aha!” moment with this cool technology, I am going to start creating samples for different use cases to compile a ‘library’ of WebSockets Architectural patterns to share with all you.
Stay tuned!