У меня написано несколько микро-сервисов, и я хочу передать некоторый пользовательский контекст в каждом запросе от одного сервиса к другому и так далее к следующему. Моя цель - использовать этот контекст контекста в каждом месте, где есть операция записи в БД в любом сервисе (я в основном хочу сохранить пользователя, ответственного за внесение изменений в БД в любом API), и я хочу сделать его легким, поэтому я попытался написать мои логики c внутри хуков ORM (используя Mon goose для MongoDb и Sequelize для MySql). Я использую cls-hooked для передачи этого пользовательского контекста внутри сервисов.
Что я делаю, так это то, что всякий раз, когда одна служба выполняет вызов другой, я добавляю некоторый пользовательский контекст к запросу через промежуточное ПО. Теперь на следующем сервисе я читаю эти переменные и устанавливаю свой контекст с ними. На этом этапе я ожидаю получить это установленное значение в любом месте, где я вызываю свою функцию namespace.get
, пока я нахожусь в том же контексте asyn c, то есть в том же потоке http-запросов. И это удерживает большую часть этого, но терпит неудачу, когда я достигаю уровня ORM.
Итак, мой код написан так: API Controller -> Некоторая утилита, которая выполняет вызов БД -> DML -> DBA -> ORM .
ORM далее вызывает его перехватчики, где я получаю доступ к заданному контексту, ORM -> ORM Hooks .
Если я пытаюсь получить доступ к своему контексту на любом из этих уровней до уровня DBA, я получаю точное значение, но если я пытаюсь получить доступ к своему заданному контексту внутри хуков ORM, я получаю ошибочные значения (наблюдаемые для быть значения из предыдущего контекста). Мне не повезло в отладке этого, я даже не догадываюсь, почему это происходит.
Моя реализация промежуточного ПО выглядит примерно так.
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();
})
}
};
Выполняется до того, как элемент управления достигает контроллеров API.
Код, который я написал для доступа к установленным значениям из контекста что-то вроде этого.
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);
}
});
Я прилагаю некоторые журналы из моего тестового прогона здесь, которые поддерживают мои наблюдения, о которых я упоминал выше. Я также прикрепил уникальный идентификатор к каждому запросу, чтобы сделать его различимым, так как все запросы выполнялись одним и тем же пользователем.
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'
}
Обратите внимание на request_id
внутри хуков ORM. К сожалению, это ломает большую часть времени. Я не понимаю, почему это работает для тех очень немногих запросов, но до достижения перехвата ORM, похоже, работает для всех запросов.
Здесь будет полезна любая помощь. Заранее спасибо:)