Preventing server timeout in node.js

Update 2013-10-08. This is an old post but continues to get page views, so clearly it is still a problem. The feature is now documented (see link below) and this post is still correct.

Original post, 2011-03-30

This is something I spent an hour or so trying to track down today, so I thought I’d write it up in the hopes that someone else is spared the trouble.

First of all, I have both web client and server written in node.js. My server is designed such that it first checks for cached versions of URLs, and if the file doesn’t exist, then it hits the database and creates the file. This second step can take a long time, and so I wanted to write a utility script that I could trigger manually to update the cache of files whenever the database changes.

So I wrote the script using javascript and node, but was getting a strange error in which the client would die if the server took longer than two minutes to complete the request. No amount of abusing the code on the client would change this, even though the node.js source code seemed to indicate that no timeout was ever being set on the client socket, and most questions on the internet were about how to limit the timeout, not set it to forever.

Turns out the suspicious setTimeout( 2 * 60 * 1000 ) in http.js at line 986 was indeed the culprit. I originally ignored that line, as it was only setting the timeout for the server-side socket. But then, after editing that line in the code and recompiling (grasping at straws), re-running the client using the recompiled node and still getting exactly 2 minutes for the socket to die, it suddenly hit me that my *server* was timing out, not my client!

So with a single undocumented call inside of the handler in question, I had no more troubles:

res.writeHead(200, { 'Content-Type': 'application/json' });
res.connection.setTimeout(0); // this could take a while

Note the second line above. While the 0.4.4 API docs don’t state this fact, the http response object exposes the socket as the connection object (I found this on the mailing list in this thread http://groups.google.com/group/nodejs/browse_thread/thread/376d600fb87f498a). So res.connection gives a hook to the Socket’s setTimeout function, and setting that to zero drops the default 2 minute limit.

November 2012 I’m still doing this in node.js 0.6.8+ 0.8.x, setTimeout is still part of net, and the http server is still by default using a 2 minute timeout. And github is still awesome.

October 2013 update. Yes, still there: 2 minute timeout. Really this isn’t a bug that needs fixing, because who wants a server to go away for two minutes in these days of attention deficit disorder web surfing. But I wish it was documented in the docs. Apparently this behavior will change soon: https://github.com/joyent/node/issues/4704

And with the release of 0.10.x, but it is now documented. See server set timeout and response set timeout.

When I modify my own code to use 0.10.x, I will put up a new post.

Arrows in threaded email in Mutt

It has been bugging me for a while that on my laptop I couldn’t see arrows in Mutt for threaded email, but instead saw **> type garbage. I access email in a bit of a convoluted way—I run rxvt-unicode, ssh into my server, attach to the screen session on that server, and switch to window 5 where I’ve logged in to the mail server. Given that three different computers were possibly contributing to the problem, I just lived with it. But after fighting with irritating line skips yesterday evening from the combination of threaded emails plus a message from someone with an accent in her name, this morning I noticed that I had no such problem on my workstation and that the arrows and accents were working just fine. So, I knew the problem was with my laptop settings.

It turns out that Slackware’s default locale is en_US. But then, further down in the file /etc/profile.d/lang.sh, there is the option to set the locale to
export LANG=en_US.UTF-8

I did that, and presto change-o, arrows and accented characters and all that appear in mutt.

It actually took longer to write this post that it did to solve the problem.