据我所知,由于 Node.js 中事件循环的性质,在请求已经移交给回调函数后,无法轻松地阻止它被处理。
由于每个事件回调与任何其他特定流程或事件无关,因此一旦将回调添加到事件循环的队列或当前正在处理,即使 request.on('timeout') 处理程序也会继续处理它被触发。
如果超时,有什么方法可以停止处理请求?我能想到的部分解决这个问题的唯一方法是在请求期间执行的每个异步回调的顶部添加一个检查,以查看请求是否超时,如果超时,则立即返回并停止连续的回调。
但是,如果已经有一个从超时请求发出的未完成的异步调用正在处理中,这并不能解决问题。在这种情况下,除非您破坏与正在执行异步处理的任何操作(例如执行 MySQL 查询)的连接,否则它将继续并最终调用与其关联的异步回调。
这在 PHP + Apache 等其他编程范例中不是问题,因为 apache 会为每个传入请求创建一个新的 PHP 进程,因此如果请求超时,该进程最终会被终止并停止整个执行流程。
有没有人遇到这个问题并找到一个现有的库或自定义方法来轻松解决这个问题?
编辑:添加一个具体的例子:
现在我们有一个内置的 API 节点处理传入的请求以跟踪分析,将请求数据发布到兔子队列,然后返回响应。如果请求进来并且由于某种原因请求需要超过 30 秒的时间来处理,它将超时并且将向客户端发送错误响应。此时,客户端将尝试再次拨打相同的电话(因此我们不会丢失分析)。
但是,由于请求本身与发布到 rabbit 的调用之间没有任何联系(除非是该请求启动了发布),因此无法停止发布该数据。因此,如果 rabbit 服务器最终完成了对发布请求的处理,现在将会有重复的数据,因为客户端现在已经发出了 2 个(或更多)请求。
阻止初始请求完成发布的唯一方法是在请求超时时破坏兔子连接。这样,初始发布就会停止,并且来自客户端的重试请求不会重复它。但是,对于在整个请求中进行的任何异步调用,都需要执行这种相同类型的手动销毁连接。如果在超时发生时我有 5 个未完成的异步调用,我将需要销毁所有 5 个异步连接(无论它们是与 rabbit、mysql、mongo 等的连接)。
但是,问题超出了请求超时时已经建立的连接。即使请求在发布到rabbit之前超时,被调用来处理该请求的函数已经执行并且不会停止,除非在各个位置进行一些检查以检查请求是否超时并返回立即地。