Connect & Restify CLS Middleware

raw JSON →
1.1.0 verified Thu Apr 23 auth: no javascript abandoned

cls-middleware provides a simple middleware for Connect and Restify (and by extension, Express) to integrate continuation-local storage (CLS) contexts into request handling. It binds each incoming request's execution flow to a dedicated CLS namespace, allowing developers to store and retrieve request-scoped data without explicit parameter passing across function calls. This package relies on the older `continuation-local-storage` library, which itself uses deprecated Node.js internal APIs or earlier experimental `async_hooks` implementations. The current stable version is 1.1.0, published in 2014, indicating it is no longer actively maintained. For modern Node.js environments (v14.5.0+), the built-in `AsyncLocalStorage` is the recommended and more performant solution for managing asynchronous context.

error TypeError: Cannot read property 'get' of undefined (or similar 'Cannot read property of null')
cause Attempting to access a CLS namespace (`ns.get()`) when no active context is available, often because `cls-middleware` was not applied, or the code is running outside of a request context.
fix
Ensure app.use(clsify(ns)) is correctly configured and executed, and that the code trying to access CLS is within the execution flow of a request handled by the middleware. Verify the namespace is correctly created.
error Error: Cannot set the key "myKey". No CLS context available, please make sure that a ClsMiddleware/Guard/Interceptor has set up the context, or wrap any calls that depend on CLS with "ClsService#run"
cause This error, or similar context loss issues, occur when code attempts to set a value in a CLS namespace after the asynchronous flow has exited the context established by the middleware, or if an intervening library broke the context chain.
fix
Identify the asynchronous operation causing the context loss. Use ns.bind(callback) to explicitly attach the current context to a callback, or ns.run(callback) to execute code within a new or existing context. Consider using AsyncLocalStorage.snapshot() or AsyncLocalStorage.bind() with modern Node.js APIs.
breaking This package relies on `continuation-local-storage`, which utilizes older, potentially unstable or deprecated Node.js internal APIs (like `async-listener` or `AsyncWrap`). This can lead to unexpected behavior or compatibility issues with newer Node.js versions.
fix Migrate to `cls-hooked` (for older Node.js if `AsyncLocalStorage` is unavailable) or preferably Node.js's native `AsyncLocalStorage` for versions 14.5.0 and above.
deprecated The `cls-middleware` package and its core dependency `continuation-local-storage` are no longer actively maintained. The last release was in 2014, and the underlying CLS mechanism has been superseded by `AsyncLocalStorage` in Node.js core.
fix Adopt Node.js's built-in `async_hooks.AsyncLocalStorage` (Node.js 14.5.0+) or community alternatives like `cls-hooked` for robust continuation-local storage.
gotcha CLS context can be lost when integrating with certain third-party middlewares or libraries that do not properly propagate `AsyncResource` contexts, such as `multer` for file uploads or some custom promise-based middleware.
fix Explicitly bind functions that might lose context using `ns.bind()` or wrap entire operations within `ns.run()`. For modern `AsyncLocalStorage`, consider `AsyncLocalStorage.bind()` or ensure middlewares are ordered correctly, usually with CLS middleware first.
gotcha Incorrect middleware ordering can prevent the CLS context from being established for certain routes or requests. If global prefixes or versioning are used, `cls-middleware` might not trigger on all routes.
fix Ensure `cls-middleware` is applied early in your Express/Connect middleware stack, ideally before any other middleware that needs access to the CLS context. For complex routing setups, manually applying it to specific routes might be necessary.
npm install cls-middleware
yarn add cls-middleware
pnpm add cls-middleware

Demonstrates setting up `cls-middleware` with Express to establish a request-scoped CLS context and retrieve data within an asynchronous operation.

const cls = require('continuation-local-storage');
const express = require('express');
const clsify = require('cls-middleware');

// Create a CLS namespace for your application
const ns = cls.createNamespace('my-app-namespace');

const app = express();

// Apply the cls-middleware to bind incoming requests to the CLS namespace
app.use(clsify(ns));

app.get('/users', function (req, res, next) {
  // Set a request-scoped value
  ns.set('userId', req.query.id || 'anonymous');

  // Simulate an async operation where the context should persist
  setTimeout(() => {
    const currentUserId = ns.get('userId');
    console.log(`Request ID: ${req.query.id || 'none'} - User ID from CLS: ${currentUserId}`);
    res.send(`Hello, User ${currentUserId}!`);
    next();
  }, 100);
});

// Start the server
app.listen(3000, () => {
  console.log('Server listening on port 3000');
});