Node.js Experiments

So I played with Node.js for a couple of months, and we even deployed a widget for MIT's OpenCourseWare at OpenStudy with it. It was a remarkably fun experience, not the least thanks to CoffeeScript, which is a fabulously awesome syntax layer over JavaScript that gets rid of many of the lamest aspects of JS sytnax (for my money, the biggest change is the ability to abbreviate function() to ->).

But, ultimately, we ran into a few issues. The biggest one was that our real-time push strategy of choice, socket.io, ended up behaving rather poorly under the kinds of load characteristics we subjected it to. MIT's pages see thousands of hits a day (that's not ginormous, by the way -- about 3 hits per minute) and users tend to stay for a few minutes.

The first issue is that we park our site behind nginx, and nginx does not speak HTTP 1.0 when proxying. The result is that WebSocket connections can't be proxied through nginx (indeed, WebSocket proxy support is currently less than spectacular, and WebSocket has since proven to have some security issues). Nothing to worry about, socket.io falls back on alternate mechanisms on the (many) browsers that are missing WebSocket support, so we should still have been okay. Moreover, we were okay for this experiment with removing ourselves from being behind nginx.

The next issue is that the static serving aspect of Node.js is not quite fleshed out yet. We were using express and connect, which come with a middleware to gzip outgoing requests. Unfortunately, it has serious performance issues, so using it at any scale is not really a good idea. Still no problems, for the purposes of our experiment, we were willing to disable gzip.

Finally, we found ourselves in a situation where Node.js would randomly quit on us with timeout errors (this appears to be a timeout firing without an associated handler or some such). After some investigation, it appeared that this was a known issue that was difficult to fix. We tried to apply some fixes to socket.io to handle this, but we were still getting the issues. Given chronic crashing, then, we couldn't keep up the experiment. We even tried switching back from node 0.3 (which may not have been supported by socket.io) to node 0.2, but this led to strange CPU spikes we didn't really have time to experiment with.

Ultimately, we turned our attention back to Lift and the improvements made to it since the 2.0 release. Between the designer-friendly views, CSS selector binding, and the inclusion of lift-mongodb, Lift is still treating us super-nicely. The compilation wait is still annoying, but in proper style I dealt with it by getting a quad-core Core i7 iMac, which tears through it a bit faster.

This shouldn't be taken to mean that I'm saying Node.js isn't ready for primetime. Obviously there are plenty of people employing it in production and loving every minute of it. It was fantastic to be able to code in JS both server- and client-side, and going back to a dynamic language was fun and exciting after a while in the statically typed world. Then again, going back to Lift after Node was also kind of cool, so I guess it's just change that I'm a fan of.

For the most part, Node treated us well. With CoffeeScript, the syntax was awesome, and the developers who are working on Node and its libraries are the kinds of passionate, fast-paced people you expect to find around surging technology. It just didn't happen to work out for us. But! All was not wasted. I did throw together a quick library for doing something very similar to Lift's view-first, CSS-selector based transformations in Node, so look for that over the next couple of days.

ADDENDUM: The timeout issues we faced with node.js are being tracked at https://github.com/joyent/node/issues/378 , where it's been mentioned that they may be gone with Node 0.4.0.