简体   繁体   中英

How to we do dynamic-scoping to implement transaction tracing in NodeJs?

I am building a client and a server side framework (NodeJs) in which I want to trace transactions. I have the ability to pass headers (transaction_id) between client and server, however, I want to be able to set the transaction_id automatically. That means that if a header is defined, a middleware should be able to read and set the transaction id in the context so that down-stream calls can read it.

Building wrappers is outside the scope of the question. What I am struggling with is being able to create a scope dynamically and storing values there.

NOTE – I am using 'strict' mode which disallows dynamic scoping in node. So need another way. NOTE – I am using Promises to make client-server calls.

Here is how I solved it finally –

I used CLS which allows us to keep track of dynamic scope.

Reading through all the text around CLS took a while, so here is a summary of what I did (layman terms)

NOTE - I am using NodeJs with 'strict' mode. This means I can't use dynamic scoping. Given its a production system, i'd want to keep strict mode. Hence an alternate way to achieve dynamic scoping.

1) CLS creates a dynamic context/scope. That allows us to then set / get key-value pairs that are visible only till we are within the created scope.

2) Since I am using Bluebird's Promises, CLS required me to use the patch to keep the context/scope available from within Promises. https://www.npmjs.com/package/cls-bluebird

3) Using CLS with Promises took time to figure out. Here is a great discussion on how different libraries have used CLS to produce different outcomes. https://github.com/TimBeyer/cls-bluebird/issues/6

4) This is how I used CLS (paraphrased and simplified) –

var cls = require('continuation-local-storage');
var clsbluebird = require('cls-bluebird');
var namespace = cls.createNamespace('ns');
clsbluebird( namespace );

var result;
namespace.run(function() {
  namespace.set('key', 'value');
  result = abc(); // returns 'value'
});

// versus doing –
result = abc(); // returns undefined

function abc() {
  return namespace.get('key');
}

5) Usecase – This way, I implemented basic tracing of transactions. Eg. NewRelic, Trace, etc.

Sequelize, one of the most popular orm does this using a module continuation local storage

Hope that helps you out

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM