Node.js 如何在Node JS中执行/中止长时间运行的任务?

Node.js 如何在Node JS中执行/中止长时间运行的任务?,node.js,multithreading,mongodb,child-process,long-running-processes,Node.js,Multithreading,Mongodb,Child Process,Long Running Processes,带有Mongo DB的NodeJS服务器—一个功能将从DB生成一个报告JSON文件,这可能需要一段时间(60秒以上—必须处理数十万个条目) 我们希望将其作为后台任务运行。我们需要能够启动报表生成过程,监视它,如果用户决定更改参数并重新生成它,则中止它 使用node最简单的方法是什么?我真的不想进入单独的工作服务器处理作业、消息队列等的领域——我们需要将其保持在同一个框中,并且实现相当简单 1) 以异步方法启动构建,并返回给用户,socket.io报告进度 2) 为构建脚本派生一个子进程 3) 使

带有Mongo DB的NodeJS服务器—一个功能将从DB生成一个报告JSON文件,这可能需要一段时间(60秒以上—必须处理数十万个条目)

我们希望将其作为后台任务运行。我们需要能够启动报表生成过程,监视它,如果用户决定更改参数并重新生成它,则中止它

使用node最简单的方法是什么?我真的不想进入单独的工作服务器处理作业、消息队列等的领域——我们需要将其保持在同一个框中,并且实现相当简单

1) 以异步方法启动构建,并返回给用户,socket.io报告进度

2) 为构建脚本派生一个子进程

3) 使用类似的东西

在我所看到的几个方法中,我被困在相同的两个方面

1) 如何监控进度? 2) 如果用户重新提交数据,如何中止现有的生成过程


非常感谢您提供任何提示…

最好将此任务与主应用程序分开。也就是说,在后台运行它很容易。 要在后台和monit中运行它而不使用消息队列等,最简单的方法是使用
子进程

  • 您可以在用户调用的端点(或url)上启动
    spawn
    作业
  • 接下来,设置一个
    套接字
    ,以返回子进程的实时监视
  • 添加另一个终结点以停止作业,该终结点具有由
    1返回的唯一id。
    (或否,取决于您的并发需要)
  • 一些编码思想:

    var spawn = require('child_process').spawn
    
    var job = null //keeping the job in memory to kill it
    
    app.get('/save', function(req, res) {
    
        if(job && job.pid)
            return res.status(500).send('Job is already running').end()
    
        job = spawn('node', ['/path/to/save/job.js'], 
        {
            detached: false, //if not detached and your main process dies, the child will be killed too
            stdio: [process.stdin, process.stdout, process.stderr] //those can be file streams for logs or wathever
        })
    
        job.on('close', function(code) { 
            job = null 
            //send socket informations about the job ending
        })
    
        return res.status(201) //created
    })
    
    app.get('/stop', function(req, res) {
        if(!job || !job.pid)
            return res.status(404).end()
    
        job.kill('SIGTERM')
        //or process.kill(job.pid, 'SIGTERM')
        job = null
        return res.status(200).end()
    })
    
    app.get('/isAlive', function(req, res) {
        try {
            job.kill(0)
            return res.status(200).end()
        } catch(e) { return res.status(500).send(e).end() }
    })
    
    为了监视您可以使用的子进程,我们在中使用它。添加监视作业的路由,并每秒调用一次。作业结束时,不要忘记释放内存



    您可能想了解一下,这将帮助您管理跨微服务的多处理。

    谢谢@soyuka的回答。使用
    job
    var-它保留对子对象的引用,因此您可以停止它-但是它在PID上工作吗?他们被重新利用了,不是吗?因此,我们生成的作业可能会完成,并且它的PID会被释放,以供任何其他新进程使用?这意味着job.kill()如果单独使用PID,可能会杀死另一个进程?或者它不是那样工作的……只要检查一下文档,它就会说。。。当信号无法传递时,可能会发出“错误”事件。向已退出的子进程发送信号不是错误,但可能会产生不可预见的后果:如果PID(进程ID)已被重新分配给另一个进程,信号将被传递给该进程。接下来会发生什么,大家都可以猜测但是根据您的exmaple,在完成时取消引用应该可以解决这个问题!!很抱歉,错过了。这段代码似乎一次只允许一个报告作业,如果试图启动第二个作业,它将覆盖(并失去对上一个作业的跟踪)。@jfriend00确实,这就是我谈到并发性需求的原因(问题中未说明)。如果您想要更多的作业,只需保留一个包含子进程的pid缓存阵列@MattBryson实际上,您必须确保在作业结束时删除内存引用(
    exit
    close
    事件)<代码>关闭与捕获信号时的
    STD
    退出
    相关。@jfriend00添加了一个条件,如果作业已经在运行。请记住,这是一个小草稿,我想给出一些关于如何做的提示,但我没有做一个完整的工作示例;)。