Как добавить в домен node.js глобальный излучатель?
В моем приложении node.js я использовал для обработки ошибок по доменам. Архитектура приложения выглядит так:
Контроллеры. Методы экспресс-вызовов вызовов контроллеров
Контроллеры вызывают сервисы и используют модели
Услуги звонить в репозитории
(На самом деле это очень похоже на DDD).
Итак, контроллеры создают домен и запускают его фактическое тело в домене. Службы обычно генерируют исключения, если что-то идет не так. Также контроллеры прослушивают ошибки домена и обрабатывают их. Это очень удобно, потому что мне не нужно беспокоиться об ошибке при вызове стека методов всех сервисов - я просто выбрасываю исключение и могу быть уверен, что он будет пойман в контроллере.
Но я столкнулся с проблемой, связанной с использованием PostgreSQL. Я использую модуль node-postgres и создаю pg.Client в отдельном js-файле, поэтому pg.Client похож на общий доступ для всех (в противном случае создание pg.Client для каждого запроса открывает множество активных соединений с postgres).
Проблема в том, что когда pg.Client определен в отдельном файле, он похож на глобальный объект и не входит в область видимости домена, созданную в контроллерах. Таким образом, исключения, сгенерированные из обратных вызовов pg.Client, не перехватываются доменом.
Я покажу упрощенный способ обработки запросов, чтобы было понятно. Допустим, пользователь хочет получить логин по userId:
Где-то в начале pg.Client создал
Получить запрос приходит на экспресс, экспресс-метод маршрутизации вызовов
Маршрутизация вызывает некоторые методы контроллера
Контроллер создает домен и вызывает в "domain.run" услугу
Служба вызывает хранилище
Репозиторий принимает pg.Client, созданный ранее, и вызывает метод SQL-запроса.
Результат метода запроса SQL помещает в обратный вызов (так что этот обратный вызов вызывается pg.Client)
И затем обратный вызов обрабатывается в сервисе, где мы проверяем, что мы получаем нулевое значение вместо пользовательской модели (потому что такого пользователя нет в db для данного userId) и генерируем исключение
Так что это исключение не перехватывается в домене. Технически, нам нужно использовать метод "add" для домена узла и добавить pg.Client, но, как я сказал, pg.Client является общим, поэтому он будет добавлен в разные параллельные домены.
Я приведу пример кода, чтобы сделать его более понятным. Это упрощенный метод UserService:
login: function (email) {
var userRepository = new UserRepository();
userRepository.findByEmail(email, function (model) {
if (model == null)
throw new Error('No such user');
});
}
Итак, этот метод "login" вызывается в домене. Но он создал userRepository, вызывает метод findByEmail, который будет использовать общий pg.Client вне области домена, и поэтому исключение не будет поймано в домене.
Есть идеи, как это исправить и поставить pg.Client в домен?
1 ответ
Я решил проблему. Я создаю EventEmitter в области активного домена и слушаю, скажем, событие "onCallback". При обратном вызове метода запроса (который не связан с доменом, поскольку pg.Client является своего рода глобальным и располагается вне домена), я генерирую "onCallback" из EventEmitter.