1

I've a couple of micro-services written and I wanna pass some user context in each request from one service to another and so forth to next. My aim is to use this set context at each place where there is a DB write operation in any service (I basically wanna store the user responsible for making the change in DB in any API) and I want to make it effortless so I tried writing my logic inside the ORM hooks (using Mongoose for MongoDb and Sequelize for MySql). I'm using cls-hooked to pass this user context within services.

What I do is, whenever one service makes call to another service, I append some user context to the request via a middleware. Now at the next service, I read those variables and set my context with them. At this point, I expect to get that set value at whatever place I call my namespace.get function as long as I'm in the same async context, aka in the same http request flow. And this hold for most part of it but gets failed as I reach towards the ORM level.

So my code is written like this, API Controller -> Some utility that makes a DB call -> DML -> DBA -> ORM.

ORM further calls it hooks where I access the set context, ORM -> ORM Hooks.

If I try to access my context at any of these levels till the DBA one, I get the accurate value, but if I try to access my set context inside ORM hooks, I get faulty values (observed to be values from previous context). I've no luck into debugging this, I don't even have a hunch for why this is happening.

My middleware implementation is something like this.

const myMiddleware = () => {
  return function (req, res, next) {
    const sessionContext = cls.getNamespace('user_context');
    sessionContext.bindEmitter(req);
    sessionContext.bindEmitter(res);
    sessionContext.run(function () {
      const contextKeys = ["user_id", "user_name"];

      for (const key of contextKeys) {
        const value = _.get(req, `query.${key}`, 'system');
        sessionContext.set(key, value);
      }

      next();
    })
  }
};

It gets executed before the control reaches the API controllers.

The code that I wrote to access the set values from context is something like this.

mySqlModel.addHook('afterCreate', async (instance, options) => {
        try {
            const userId = UserContext.get("user_id");
            const userName = UserContext.get("user_name");
            // utilise them here
        } catch (err) {
             console.error(err);
        }
    });

I'm attaching some of the logs from my test run here that supports my observations I mentioned above. I also attached a unique id to each request to make it distinguishable as I made all requests using the same user.

DML:: { _ns_name: 'user_context',
id: 233, // async context ID
user_id: 'johnwick', 
request_id: 'c0b2e4105a562be4c33ef20291cbf286'
}
DBA:: { _ns_name: 'user_context',
id: 233,
user_id: 'johnwick', 
request_id: 'c0b2e4105a562be4c33ef20291cbf286'
}
Hooks:: { _ns_name: 'user_context',
id: 233,
user_id: 'johnwick', 
request_id: 'c0b2e4105a562be4c33ef20291cbf286'
}

DML:: { _ns_name: 'user_context',
id: 565,
user_id: 'johnwick', 
request_id: '54a290e131af1696814bfe1bfb077b1c'
}
DBA:: { _ns_name: 'user_context',
id: 565,
user_id: 'johnwick', 
request_id: '54a290e131af1696814bfe1bfb077b1c'
}
Hooks:: { _ns_name: 'user_context',
id: 233,
user_id: 'johnwick', 
request_id: 'c0b2e4105a562be4c33ef20291cbf286'
}

DML:: { _ns_name: 'user_context',
id: 780,
user_id: 'johnwick', 
request_id: '3fd4e67a6eb633898db2bce8dbc83416'
}
DBA::  johnwick 3fd4e67a6eb633898db2bce8dbc83416 { _ns_name: 'user_context',
id: 780,
user_id: 'johnwick', 
request_id: '3fd4e67a6eb633898db2bce8dbc83416'
}
Hooks:: { _ns_name: 'user_context',
id: 233,
user_id: 'johnwick',
request_id: 'c0b2e4105a562be4c33ef20291cbf286'
}

DML:: { _ns_name: 'user_context',
id: 1134,
user_id: 'johnwick', 
request_id: '748e8b06d93e560ff15486d16a669342'
}
DBA:: { _ns_name: 'user_context',
id: 1134,
user_id: 'johnwick', 
request_id: '748e8b06d93e560ff15486d16a669342'
}
Hooks:: { _ns_name: 'user_context',
id: 233,
user_id: 'johnwick', 
request_id: 'c0b2e4105a562be4c33ef20291cbf286'
}




DML:: { _ns_name: 'user_context',
id: 2087,
user_id: 'johnwick',
request_id: '19898d61be3b7c3c3831266654b9e161'
}
DBA:: { _ns_name: 'user_context',
id: 2087,
user_id: 'johnwick', 
request_id: '19898d61be3b7c3c3831266654b9e161'
}
Hooks:: { _ns_name: 'user_context',
id: 2087,
user_id: 'johnwick', 
request_id: '19898d61be3b7c3c3831266654b9e161'
}


DML:: { _ns_name: 'user_context',
id: 2397,
user_id: 'johnwick', 
request_id: 'b47fb609a0c837f76e32bf6c1872389b'
}
DBA:: { _ns_name: 'user_context',
id: 2397,
user_id: 'johnwick', 
request_id: 'b47fb609a0c837f76e32bf6c1872389b'
}
Hooks:: { _ns_name: 'user_context',
id: 2087,
user_id: 'johnwick', 
request_id: '19898d61be3b7c3c3831266654b9e161'
}

Notice the request_id inside the ORM hooks. Sadly, it breaks most of the time. I don't get why this works for those very few requests but before reaching ORM hooks, it seems to work for all the requests.

Any help would be appreciated here. Thanks in advance :)

0 Answers0