nodejs

The Perils of Node Continuation-Local-Storage

This post describes my experience with node continuation-local-storage whilst working on an enterprise node application

Continuation-Local-Storage. Quite a mouthful. Or cls as i will refer to it from now.

Note: This post explains cls better than i could and helped me to fully grasp the solution for the problem i was trying to solve.

We were working on an enterprise cloud solution for a major bank. My responsibility was to design the front end and the server that it communicates with. The server was implemented using StrongLoop’s Node.js api framework LoopBack. The node version was 0.12.x.

One key requirement was to provide logging that can be aggregated to monitor various metrics. After choosing winston as our logger we set about logging the information that was required.

This posed a few challenges:

  • Last thing we wanted was a number of free-from ad hoc logging statements littered all over the place
  • Given the nature of asynchronous node with callbacks and promises, we wanted to be able to log a request until completion.

In the Java world, this would be achieved using thread local storage. As stated on the cls website:

Continuation-local storage works like thread-local storage in threaded programming, but is based on chains of Node-style callbacks instead of threads. 

LoopBack provides a way to retrieve the current context within a request. Perfect.

Except in some cases if there is code that invokes a callback or promise, then the context returned null. This became more apparent whenever there was an error. It was hard to track down the contextual information for that error. We could always get some of the information from the Request but all the information that was collected down the chain was lost.

Google revealed lots of similar issues on the StrongLoop forums such as this and this. After many days of frustration i stumbled upon the article i mentioned at the top of this post and that cleared up most of my misconceptions.

Bottom line is, if the library you are calling does not support cls, it wont work. This is something that is not apparent or clearly documented. We were using bluebird which can be monkey patched using cls-bluebird. If there is no cls-* modules, then you can bind the callback.


var ctx = loopback.getCurrentContext();

getUsers(ctx.bind(function(err, users) {

  if (err) {
    return next(err);
  }

  res.send(users);
}));

I don’t like the idea of monkey patching libraries. I can envision many enterprise applications having similar requirements.

So what are the options and the alternatives:

Each of these options require writing extra code to be able to handle the propagation of context. None of these are entirely satisfactory, nor is there any indication as to what the best pattern is. But when i find it, i hope to document it.

If i were to start again would i use node? Absolutely.  One of the best things is that its easy to be productive with node and develop an application in next to no time (take that with a pinch of salt) compared to doing the same in something like java. Working with node has been a learning experience and i look forward to continue on this journey.

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn