node-continuation-local-storage icon indicating copy to clipboard operation
node-continuation-local-storage copied to clipboard

namespace set values are getting lost in http socket close callback

Open queston02 opened this issue 4 years ago • 2 comments

We are creating the namespace and setting a variable called gtid in one of the middle ware and then trying to read that value for logging. We are getting the values in most of the places but some places it's undefined. One of the place is in the callback of the socket close event. Below is the code to provide some context.

var express = require('express');
var app = express();
var http = require('http');
var continuationLocalStorage = require('continuation-local-storage');
var namespace = continuationLocalStorage.createNamespace('namespace');

app.use(function (req, res, next) {
    namespace.run(function () {
        namespace.set('gtid', 'some unique value');
        return next();
    });
});

var req = protocol.request(request, function (response) {
    response.setEncoding('utf-8');
    var responseBody = '';

    response.on('data', function (data) {
        responseBody += data;
    });

    response.on('error', function (e) {
        e.code = response.statusCode;
        return callback(e);
    });

    response.on('end', function () {
        return callback(null, responseBody);
    });
});

req.on('socket', function (socket) {
    if (!socket.name) {
        socket.name = new Date().getTime();

        socket.on('close', function () {
            var namespace = getNamespace('namespace');
            console.log(namespace.get('gtid'))
        });
    }
});

req.on('error', function (e) {
    return callback(e);
});

if (request.body) {
    req.write(request.body);
}
req.end();

queston02 avatar Sep 04 '20 23:09 queston02

There is one more place where variable set in namespace is coming as undefined. It's in the callbacks defined in the express.router. Please see below for some context.

const express = require('express');
const router = express.Router();

router.post('/dummy', sessionValidator, setJson.bind(dummyProduct, 'getDummyProducts'));

function sessionValidator(req, res, next) {
    var namespace = getNamespace('namespace');
    console.log(namespace.get('gtid'))
}

queston02 avatar Sep 09 '20 21:09 queston02

I encountered the same issue. The problem is that next callback finishes before the other stuff get called, so I looked at the Namespace.prototype.run source and took what I needed from it. Beware though, I'm reusing the same namespace without destroying it which means that there's a small chance for a race condition, in which a request overwrites the 'req' value before the previous request is done with it (for me it wasn't a concern):

const CLS = require('continuation-local-storage');

function cls(req, res, next) {
  let namespace = CLS.getNamespace('api') || CLS.createNamespace('api');
  let context = namespace.createContext();
  namespace.enter(context);
  try{
    namespace.set('req', req);
    namespace.set('res', res);
    return next();
  } catch (e) {
    console.log('CLS ERR: ' + e);
  }
}

...
app.use('/api/*', cls);

avico81 avatar Nov 10 '20 14:11 avico81