Asynchronous local storage implementation which provides an agnostic and performant approach no matter your version of node.
This package is a wrapper around both the populer cls-hooked library as well as the Node v13+ AsyncLocalStorage.
It will choose the right one to implement based on your version of Node.
This library is great for creating a thread local like implementation for your Express, Koa, Fastify, or Restify implementations to provide a local store per call. This library ensures that all values stored within a scope will only pertain to that scope (scope creep in this instance is lethal to data integrity).
For instance, if you are using an ORM and you have some type of beforeHooks to save user information. You could try to save the calling user's information in some pre request handler by storing a value in a service to be used later by the hooks to save the proper user making the api call. However, if another user made a simultaneous call, someone's info could/would be overwritten in this case. This library ensures that will not happen.
The following examples show how this can be set up in some of the more familiar Node API frameworks. These examples can be run from the examples directory.
const fastAls = require('fast-als');
const fastify = require('fastify')({ logger: true })
fastify.addHook('onRequest', (req, reply, done) => {
fastAls.runWith({
user: { id: 'system' } // sets default values
}, () => {
done();
});
});
fastify.addHook('preHandler', (req, reply, done) => {
// overrides default user value
fastAls.set('user', { id: 'fastifyUser' });
done();
});
// Declare a route
fastify.get('/', async (request, reply) => {
return {
user: fastAls.get('user')
}
});
// Run the server!
const start = async () => {
try {
await fastify.listen(3000);
fastify.log.info(`server listening on ${fastify.server.address().port}`);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
}
start();
const fastAls = require('fast-als');
const express = require('express')
const app = express()
const port = 3000
app.use((req, res, next) => {
fastAls.runWith({
// overrides default user value
user: { id: 'system' } // sets default values
}, () => {
next();
});
});
app.use((req, res, next) => {
fastAls.set('user', {
id: 'expressUser'
});
next();
});
app.get('/', (req, res) => res.send({ user: fastAls.get('user') }))
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
const fastAls = require('fast-als');
const restify = require('restify');
var server = restify.createServer();
server.pre(function (req, res, next) {
fastAls.runWith({
user: { id: 'system' } // sets default values
}, () => {
next();
});
return;
});
server.use(function (req, res, next) {
// overrides default user value
fastAls.set('user', { id: 'restifyUser' });
next();
});
server.get('/', (req, res, next) => {
res.send(fastAls.get('user'));
});
server.listen(8080, function () {
console.log('%s listening at %s', server.name, server.url);
});
Asynchronous Local Storage wrapper that will run regardless of Node version.
The start of creating an asynchronous local storage context. Once this method is called, a new context is created where get and set calls will set and return values as expected.
defaults
object Sets the default values. A convenience so that you don't have to check to see if a value is there and set it to something else.callback
fastAls~runWithCallback This is the code to be executed first within the new context that is created
const fastAls = require('fast-als');
function firstCallInScope() {
// override user
fastAls.set('user', { id: 'overwrittenUser'});
}
function secondCallInScope() {
// will print the user set in firstCallInScope
console.log(fastAls.get('user'));
}
fastAls.runWith({ user: { id: 'someUser' } }, () => {
firstCallInScope();
secondCallInScope();
});
Sets a variable for a given key within running context (started by runWith). If this is called outside of a running context, it will not store the value.
key
string the key to store the variable byvalue
any the value to store under the key for lookup later on.
const fastAls = require('fast-als');
function callInScope() {
// override user
fastAls.set('user', { id: 'overwrittenUser'});
}
fastAls.runWith({ user: { id: 'someUser' } }, () => {
callInScope();
});
const fastAls = require('fast-als');
function callOutOfScope() {
// this never gets set
fastAls.set('user', { id: 'overwrittenUser'});
}
// calling this won't store the variable under the key
callOutOfScope();
Gets a variable previously set within a running context (started by runWith). If this is called outside of a running context, it will not retrieve the value.
key
string the key to retrieve the stored value
const fastAls = require('fast-als');
function callInScope() {
// prints default user
console.log(fastAls.get('user'));
}
fastAls.runWith({ user: { id: 'someUser' } }, () => {
callInScope();
});
const fastAls = require('fast-als');
function callInScope() {
// prints default user
console.log(fastAls.get('user'));
}
fastAls.runWith({ user: { id: 'someUser' } }, () => {
callInScope();
});
// calling this will return undefined
callInScope();
The code to be executed after the new asynchronous local storage context is created.
Type: Function