在单独的线程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中有很多模块可以做到这一点,例如:
- http://automattic.github.io/kue/
- https://www.npmjs.com/package/bull
- https://www.npmjs.com/package/bee-queue
- https://www.npmjs.com/package/node-taskman
- https://www.npmjs.com/package/cluster-master
- https://www.npmjs.com/package/agenda
- https://www.npmjs.com/package/worker-farm
请参阅这些模块的文档,以查看哪一个最适合您的需求。