在单独的线程NodeJs中运行长时间运行的快速API进程

我有一个API调用需要大约5-10分钟的时间来处理。 我设置了一个超时方法,这样我就可以立即获得一个排队状态的API响应。

下面简单的视觉

doWork(object) => { /*... Takes 5 minutes */ } app.post('/longProcess',(req,res)=> { setTimeout(this.doWork(req.body), 1000); res.send({ status: 'queued' }); }) 

这对第一个请求立即作出回应的作品。 但第二个请求被locking,等待doWork完成。

而不是使用SetTimeout,我真正想要做的就是将longProcess发送到一个单独的单线程队列和逐一处理这些。

有什么build议么?

问题

问题不在于doWork()需要花费很多时间,而是显然在整个生命周期中阻塞了线程,并且不会让事件循环运行。

可能的原因

这可能是由几件事情引起的,我只能在这里猜测,因为你没有显示doWork()的来源,甚至描述了它的作用和方式。 例如:

  • 您的doWork()可能会使用阻止操作,如fs.readFileSync()或其他名称为Sync函数。
  • 你的doWork()可能有一个for或者while循环,这个循环会旋转5-10分钟,并且在这个过程中阻塞事件循环。
  • 您的代码会执行一些严重的数字运算,这些运算没有分成让事件循环在这些步骤之间滚动的步骤。

一般来说,如果doWork()不阻塞主线程,可能需要几个小时才能运行,并且不应该阻止其他连接在一毫秒内被服务。

解决scheme

停止阻塞线程

这个问题的最简单的解决scheme可能是避免阻塞函数调用(那些具有Sync后缀或您自己的函数),长时间运行的循环和大量的计算,不分成短的步骤。

举些例子:

  • 而不是使用readFileSync()使用readFile()
  • 使用process.nextTick()而不是长时间运行/ while循环,
  • 而不是非常深的recursion(可能感谢TCO),使用循环分成与process.nextTick()

如果上述解决scheme无法应用(由于我对doWork()函数一无所知,所以我没有办法知道),那么您可以采取另一种方法。 还有其他一些你可以做的事情。

产生一个过程

另一个解决scheme是使用child_process在每次启动长时间运行的任务时产生一个不同的进程。 当孩子结束工作并做出相应的反应时,你的主要过程可以得到通知,但是在等待时不会被阻塞。 请参阅: https : //nodejs.org/api/child_process.html

使用一个队列

您也可以使用待处理作业的队列,并通过其他进程处理它们,而不影响您的主程序,只会计划新任务,而不执行或等待它们。 通常这样的队列是用Redis完成的,但是也可以用CouchDB或MongoDB来完成。 您需要有一些中央注册处,您的工作进程可以从中处理这些任务。 在Node中有很多模块可以做到这一点,例如:

请参阅这些模块的文档,以查看哪一个最适合您的需求。