如何在node.js域全局发射器中添加?(How to add in node.js domain global emitter?)

在我的node.js应用程序中,我曾经通过域处理错误。 该应用程序的架构如下所示:

控制器。 Express路由调用控制器方法

控制器调用服务并使用模型

服务调用存储库

(实际上它与DDD非常相似)。

因此,控制器创建域,并在域中运行其实际主体。 如果出现问题,用于抛出异常的服务。 控制器也会侦听域错误并对其进行处理。 它非常舒服,因为我不需要担心在所有服务的方法callstack上运行错误 - 我只是抛出一个异常并且可以确定它会被控制器捕获。

但是我遇到了使用PostgreSQL的问题。 我使用node-postgres模块并在分离的js文件中创建pg.Client,因此pg.Client就像为每个人共享一样(否则,在每个查询上创建pg.Client会使用postgres打开大量活动连接)。

问题是,当pg.Client在分离文件中定义时,它就像一个全局对象,并且它不包含在控制器中创建的域范围中。 因此,pg.Client回调抛出的异常不会被域捕获。

我将展示请求处理的简化方式以使其清楚。 假设用户想要通过userId登录:

在创建的初始化pg.Client中的某处

获取请求来快递,快递呼叫路由方法

路由调用一些控制器的方法

Controller在“domain.run”服务中创建域和调用

服务调用存储库

存储库将pg.Client创建为ealier,并调用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放入域中?

In my node.js application i used to handle error by domain. The architecture of the app looks like:

Controllers. Express routing calls controllers methods

Controllers call services and use models

Services call repositories

(Actually it's quite similar to DDD).

So, controllers create domain, and run its actual body in the domain. Services used to throw exceptions if something's going wrong. Also controllers listen for domain errors and process them. Its very comfortable because i dont need to worry about carring an error over all services's method callstack — i just throw an exception and can be sure that it would be caught in controller.

But i have faced a problem connected with using PostgreSQL. I use node-postgres module and i create pg.Client in separated js file, so pg.Client is like shared for everybody (otherwise, creating pg.Client on each query makes open lots of active connections with postgres).

The problem is that when pg.Client is definded in separated file it's like a global object and it's not included in domain scope created in controllers. So exceptions throwed from pg.Client callbacks are not caught by domain.

I will show simplified way of request processing to make it clear. Let's say user wants to get login by userId:

Somewhere in the beggining pg.Client created

Get request comes to express, express call routing method

Routing calls some of controller's method

Controller creates domain and calls in «domain.run» a service

Service calls a repository

Repository takes pg.Client created ealier, and calls sql query method

Result of sql query method puts in callback (so this callback is called by pg.Client)

And then the callback is processed in service, where we check that we get null instead of user model (because there is no such user in db for given userId) and throw an exception

So that exception is not caught in domain. Technically, we need to use «add» method of node domain and add pg.Client, but how i said pg.Client is shared, hence it would be added in different concurrent domains.

I will list some code example to make it more clear. It's simplified method of UserService:

login: function (email) { var userRepository = new UserRepository(); userRepository.findByEmail(email, function (model) { if (model == null) throw new Error('No such user'); }); }

So, that method «login» is called in domain. But it created userRepository, calls findByEmail method which will use shared pg.Client laying outside of domain's scope, and that's why exception will not be caught in domain.

Any ideas how to fix it and put pg.Client in the domain?

最满意答案

我解决了这个问题。 我在活动域的范围内创建EventEmitter并监听让我们说«onCallback»事件。 在回调查询方法(与域没有关联,因为pg.Client有点全局并且放置域)时,我发出了EventEmitter的«onCallback»。

I solved the issue. I create EventEmitter in scope of active domain and listen lets say «onCallback» event. In callback of query method (which is not connected with the domain, because pg.Client is kinda global and lays out of the domain) i emit «onCallback» of the EventEmitter.

更多推荐