请求超时时停止处理请求

时间:2013-10-29 18:40:05

标签: node.js timeout request

据我所知,由于Node.js中事件循环的性质,在将请求传递给回调函数之后,无法轻松阻止处理请求。

由于每个事件回调都没有绑定到任何其他特定的流程或事件,一旦将回调添加到事件循环的队列或当前正在处理,即使request.on('timeout',它也将继续处理')处理程序被触发。

如果请求超时,有没有办法停止处理?我能想到部分解决这个问题的唯一方法是在请求期间执行的每个异步回调的顶部添加一个检查,以查看请求是否已超时,如果有,则立即返回并停止连续的回调。

但是,如果已经处理了由超时请求处理的未完成的异步调用,则这不能解决问题。在这种情况下,除非你破坏与异步处理(例如执行MySQL查询)的连接,否则它将继续并最终调用与之关联的异步回调。

这在其他编程范例(如PHP + Apache)中不是问题,因为apache为每个传入请求创建一个新的PHP进程,因此如果请求超时,则最终会终止该进程并停止整个执行流程。

是否有人遇到此问题并找到了现有的库或自定义方式来轻松解决此问题?

编辑:添加一个具体的例子:

现在我们有一个内置API的节点,用于处理传入的请求以跟踪分析,将请求数据发布到兔子队列,然后返回响应。如果请求进入并且由于某种原因请求的处理时间超过30秒,它将超时并且将向客户端发送错误响应。此时,客户端将尝试再次进行相同的呼叫(因此我们不会丢失分析)。

但是,由于请求本身与发布到Rabbit的调用之间没有任何关联(除了启动发布的请求之外),没有办法停止发布该数据。因此,如果兔子服务器最终完成处理发布请求,那么现在将存在重复数据,因为客户端现在已经发出了2个(或更多)请求。

停止初始请求完成发布的唯一方法是在请求超时时销毁Rabbit连接。这样,初始发布将停止,来自客户端的重试请求将不会复制它。但是,对于在整个请求中进行的任何异步调用,都需要执行相同类型的手动销毁连接。如果在超时发生时我有5个未完成的异步调用,我将需要销毁所有5个异步连接(无论它们是连接到rabbit,mysql,mongo等)。

然而,问题超出了请求超时时已经建立的连接。即使请求在发布到Rabbit之前超时,调用处理该请求的函数也已经执行并且不会停止,除非在各个位置进行一些检查以检查请求是否已超时并返回立即

1 个答案:

答案 0 :(得分:1)

您可能会通过更具体的问题获得更好的答案。像“一个mysql查询”这样的技术细节比模糊的非技术术语(如“请求”)更容易讨论。

  

我能想到部分解决这个问题的唯一方法是在请求期间执行的每个异步回调的顶部添加一个检查,以查看请求是否已超时,如果有,则返回立即停止连续的回调

你现在没有,也不会在node.js中需要这样的代码。没有人这样做,因为这不是问题。即使是这样,在堆栈中解决低于应用程序的问题也是有意义的。

  

这在其他编程范例(如PHP + Apache)中不是问题,因为apache为每个传入请求创建一个新的PHP进程,因此如果请求超时,则最终会终止该进程并停止整个执行流程。

这甚至比node.js中的问题更少,因为对于传入的HTTP请求,甚至没有新进程甚至是新线程。发生的最终结果基本上是:

  • 客户端连接并发送GET请求
  • OS接收连接
  • 节点收到GET请求
  • 我们假设此时客户端进程(浏览器)在客户端计算机上突然被杀死
  • 究竟如何发挥作用有几个场景。如果电源在浏览器所在的房子里熄灭,则没有任何东西通过电线,在其他情况下,客户端我发送数据包以提前关闭TCP连接。
  • 在节点方面并不重要。您处理请求,进行数据库查询,呈现HTML,最糟糕的情况是,一旦完成工作,没有人关心,但它只是一个GET请求。您的应用程序应该每秒执行许多这样的操作。考虑完成将该请求处理为“问题”是错误的。这不是一个问题,也没有任何我曾经听说过的任何编程语言可以实现的事情。服务器实际上无法区分正确等待200ms之前断电的客户端响应的客户端。 HTTP没有“CANCEL”方法。实际上,完成整个HTTP请求可能在语义上更正确。例如,如果Web浏览器向您发送完整的HTTP POST以进行信用卡购买,但在您响应之前断开连接,则该事务应该完成。在启动后中止它将是不正确的。