Context for async programming in nodejs
npm install @onelogin/node-async-contextIt works like thread-local storage in threaded programming, but is based on async hooks that were added into NodeJS in v8.1.0.
Warning: async hooks are marked as experimental feature; therefore, node-async-context shouldn't be used for storing any critical data in production
Keep context per request in an express app
- Correlation ID / Request ID - API gateway assign you correlation ID that you want to attach to any log entry, error report or as header when calling an upstream service related to the request
- metrics - collect metrics related to request, time spent waiting for response from DB, upstream service, etc
Simple express middleware that initialize context and put there Correlation ID received from API gateway:
``javascript
const { enable, context } = require("@onelogin/node-async-context");
enable();
module.exports = (req, res, next) => {
// creates a new context and bind it to current execution (request)
context.create();
// reads correlation ID from request header and store it into context
context.set("correlation-id", req.get("X-Correlation-ID"));
next();
};
`
Configure Winston logger to read Correlation ID from context and make it part of every log entry:
`javascript
const winston = require("winston");
const { context } = require("@onelogin/node-async-context");
const formatter = entry => {
return ${entry.level}: ${entry.message} - CID: ${context.get(
"correlation-id"
)};
};
module.exports = () => {
const logger = new winston.Logger({
transports: [
new winston.transports.Console({
formatter
})
]
});
return logger;
};
`
Read Correlation ID from context and setting it as HTTP header when calling an upstream service:
`javascript
const superagent = require("superagent");
const { context } = require("@onelogin/node-async-context");
module.exports = {
listUsers: () => {
return (
superagent
// send GET request to /users via superagent HTTP client
.get(/users)`
// set X-Correlation-ID header based on correlation ID from shared context
.set("X-Correlation-ID", context.get("correlation-id"))
);
}
};
node-async-context exports:
enables async hooks that powers context; you app will start to listen to async hooks; without calling enable() context won't work
object with following methods:
- create() creates an empty context and bind it to current execution (set current execution as root of async executions tree which share the same context; in other words, it sets scope of created context to start from this point).set(key, value)
- set value into current context (key-value store) under given keyget(key) => value` get value from current context (key-value store) for given key
-
cleanup method - it disable async hooks and clean storage with contexts