Почему мой текущий контекст, перехваченный Cls, становится таким же, как предыдущий, при доступе на уровне перехватчиков ORM? - PullRequest
0 голосов
/ 13 апреля 2020

У меня написано несколько микро-сервисов, и я хочу передать некоторый пользовательский контекст в каждом запросе от одного сервиса к другому и так далее к следующему. Моя цель - использовать этот контекст контекста в каждом месте, где есть операция записи в БД в любом сервисе (я в основном хочу сохранить пользователя, ответственного за внесение изменений в БД в любом 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, похоже, работает для всех запросов.

Здесь будет полезна любая помощь. Заранее спасибо:)

...