在我的 node.js 应用程序中,我曾经按域处理错误。该应用程序的架构如下所示:
控制器。快速路由调用控制器方法
控制器调用服务和使用模型
服务调用存储库
(其实和DDD很像)。
因此,控制器创建域,并在域中运行其实际主体。如果出现问题,服务会抛出异常。控制器还监听域错误并处理它们。它非常舒服,因为我不需要担心在所有服务的方法调用堆栈上出现错误——我只是抛出一个异常并且可以确定它会在控制器中被捕获。
但是我遇到了与使用 PostgreSQL 相关的问题。我使用 node-postgres 模块,并在单独的 js 文件中创建 pg.Client,因此 pg.Client 就像为所有人共享(否则,在每个查询上创建 pg.Client 会打开许多与 postgres 的活动连接)。
问题在于,当 pg.Client 在单独的文件中定义时,它就像一个全局对象,并且不包含在控制器中创建的域范围内。因此从 pg.Client 回调抛出的异常不会被域捕获。
我将展示简化的请求处理方式以使其清楚。假设用户想通过 userId 登录:
在开始的 pg.Client 创建的某个地方
获取请求来快递,快递调用路由方式
路由调用一些控制器的方法
控制器创建域并在 «domain.run» 中调用服务
服务调用存储库
Repository 获取之前创建的 pg.Client,并调用 sql 查询方法
sql查询方法的结果放入回调中(所以这个回调被pg.Client调用)
然后回调在服务中处理,我们检查我们得到 null 而不是用户模型(因为给定 userId 在 db 中没有这样的用户)并抛出异常
因此该异常不会在域中捕获。从技术上讲,我们需要使用节点域的 «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 放入域中?