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

Pro*_*imo 5 queue multithreading node.js express

我有一个API调用需要大约5-10分钟来处理.我在它周围设置了一个超时方法,以便我得到一个状态为排队的即时API响应.

简单的视觉如下

doWork(object) => { /*... Takes 5 minutes */ }

app.post('/longProcess',(req,res)=> {
    setTimeout(this.doWork(req.body), 1000);
    res.send({ status: 'queued' });
})
Run Code Online (Sandbox Code Playgroud)

这适用于第一个立即响应的请求.但第二个请求被锁定等待doWork完成.

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

有什么建议?

rsp*_*rsp 19

问题

问题不是doWork()需要花费很多时间,而是它显然会在整个生命周期中阻塞你的线程,并且不会让事件循环有任何机会运行.

可能的原因

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

  • doWork()可以在其名称中使用阻止操作fs.readFileSync()或其他功能Sync.
  • doWork()可能有一个forwhile循环旋转5-10分钟并阻止事件循环这样做.
  • 你的代码执行了一些严重的数字运算,没有分为让事件循环在这些步骤之间滚动的步骤.

一般来说,doWork()如果它不阻塞你的主线程你可能需要几个小时才能运行它不应该阻止其他连接即使在一毫秒内也没有服务.

解决方案

停止阻止线程

解决该问题的最简单方法可能是避免阻塞函数调用(具有Sync后缀或您自己的函数的调用),长时间运行的循环以及不分为短步骤的繁重计算.

举些例子:

  • 而不是readFileSync()使用readFile()
  • 而不是长时间运行/ while循环,使用 process.nextTick()
  • 而不是非常深的递归(可能由于TCO),使用循环分为部分 process.nextTick()

如果上述解决方案无法应用(因为我对你的doWork()功能一无所知,我无法说出来),那么你可以采取另一种方法.还有一些你可以做的事情.

产生一个过程

另一种解决方案是child_process每次启动长时间运行的任务时使用生成不同的进程.当孩子结束工作并做出相应反应时,可以通知您的主要流程,但在等待时不会被阻止.请参阅:https://nodejs.org/api/child_process.html

使用队列

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

请参阅这些模块的文档,以了解哪种模块最适合您的需求.