Tales of the minotaur or long polling with node.js

14 Mar 2011

It’s been a while since I started playing with node.js and server side JavaScript, therefore building something “non-trivial” and potentially useful become a necessity. I also like to play with real-time server side stuff and node.js is a perfect framework for doing these kinds of chatty applications. WebSockets have still some time to go mainstream and not all of the web browsers supports them (for example webapp developers most beloved IE), so I decided to create a “simple” long poll server called minotaur. This article is mainly about certain parts of minotaur server and it’s architecture, but I hope it will also help others during the development of similar systems.

Long polling principle

The principle of long polling described in wikipedia article is pretty straight forward:

“The browser makes an Ajax-style request to the server, which is kept open until the server has new data to send to the browser, which is sent to the browser in a complete response. The browser initiates a new long polling request in order to obtain subsequent events.”

There are however few issues, or architectural decisions, which needs to be solved in order to start building a long poll server. Solutions and patterns used to solve these issues can affect crucial elements such as performance, security or stability of the server.

Communication transport between server and client

There are numerous ways which can be used to asynchronously communicate between server and client including WebSockets, Flash Sockets, XMLHttpRequests or AJAX multipart streaming. However some browsers doesn’t support Cross-Origin Resource Sharing to solve same origin policy, therefore, the only cross-browser compatible way is to use JSONP polling as transport method.

Server side session management

At first I was using linked list data structure copied from node-websocket-server because I liked the coding style and it seemed to be pretty fast. But after some time I realized that the most frequent operation on stored sessions is indexing or random access which have not so cool O(n) complexity when linked list is used. Therefore, after some consultation at StackOverflow, I switched the data structure to plain old JavaScript object where stored sessions act more like a hash table. The result was slightly faster reaction times and less memory consumption.

Identification of polling clients

When the client sends the first request to the server, it needs to be further uniquely identified by some sort of session ID which will serve as a key identifier for the next polling requests, otherwise the server wouldn’t be able to maintain connection with a client. Again after some consultation with folks at StackOverflow I decided to use signed secure cookies generated by cookie-node node.js module. When new poll request is sent to the server, client is identified based on the session ID stored in a secure cookie which is decrypted on the server side.

Session reusing

Secure cookie is assigned to the browser context, but user can open multiple tabs with the same long polling web application within one browser. This can lead to serious problems during long polling therefore assigned session should be reused for each new tab which requires separate polling connection. Minotaur server solves this issue by creating a new client connection for each new long polling tab. This client connection have it’s own unique ID used for identification and is created withing existing session which keeps track of concurrently polling clients. Number of these parallel connections within one browser is restricted by the specific browser.

Future releases

With WebSockets approaching I will probably extend minotaur server communication transports with this great technology and leave JSONP polling as fallback option for situations where WebSockets can’t be used. You can find source codes of the minotaur together with two chat example web applications which are using this long poll server at github.

blog comments powered by Disqus