Nodejs:在Windows上向子进程发送Ctrl+C

6

你好,我正在使用child_process.spwan在Windows上启动运行Python脚本的子进程。该脚本监听SIGINT以优雅地退出自身。但是Windows不支持信号,所有node只是模拟了它。因此,在Windows上使用child_process.kill('SIGINT')实际上是无条件地杀死进程(没有优雅的退出,Python的SIGTERM / SIGINT处理程序不会被调用)。同时,向stdin写入ctrl+c字符也不起作用。

当我查看Python API时,我发现了CTRL_BREAK_EVENT和CTRL_C_EVENT可以满足需求。我想知道node是否有类似这些的特定于平台的API?

相关帖子但不起作用: 如何发送控制C node.js和child_processes 使用stdin.write()向node.js生成的childprocess发送crtl+c?


据说这是不可能的:https://dev59.com/B57ha4cB1Zd3GeqPnr39#41976985 - Paul
2个回答

1
你可以使用IPC消息向子进程发出信号,告知其停止并优雅地终止。下面的方法使用 process.on('message') 在子进程中监听来自父进程的消息,使用child_process.send()从父进程发送消息到子进程。下面的代码设置了1分钟的超时时间,以便在子进程挂起或花费过长时间完成时退出。

py-script-wrapper.js

// Handle messages sent from the Parent
process.on('message', (msg) => {
  if (msg.action === 'STOP') {
    // Execute Graceful Termination code
    process.exit(0); // Exit Process with no Errors
  }
});

父进程

const cp = require('child_process');
const py = cp.fork('./py-script-wrapper.js');

// On 'SIGINT'
process.on('SIGINT', () => {
  // Send a message to the python script
  py.send({ action: 'STOP' }); 

  // Now that the child process has gracefully terminated
  // exit parent process without error
  py.on('exit', (code, signal) => {
    process.exit(0);
  });

  // If the child took too long to exit
  // Kill the child, and exit with a failure code
  setTimeout(60000, () => {
    py.kill();
    process.exit(1);
  });

});

3
谢谢。当子进程是一个节点进程时,这确实可行。但如果最终我需要生成一个Python进程(例如 spawn('python', ['myscript.py'])),它持有一些资源(例如套接字),但完全不懂JavaScript。如何以跨平台的方式进行与Python进程之间的进程间通信? - mingyuan-xia

0
你可以通过标准输入(stdin)向Python进程发送“quit”命令,这对我很有效。在Python中,你需要创建一个线程来使用input从stdin读取数据,一旦返回,就设置一个事件标志。在你的主应用程序循环中,你定期检查事件是否已经被设置并退出程序。

Python应用程序(script.py):

import threading
import sys

def quit_watch(event):
    input("Type enter to quit")
    event.set()

def main():
    stop = threading.Event()
    threading.Thread(target=quit_watch, args=[stop]).start()

    while True:
        # do work, regularly check if stop is set
        if stop.wait(1):
            print("Stopping application loop")
            break

if __name__ == '__main__':
    main()
    sys.exit(0)

Node.js 应用程序:

child_process = require('child_process')
child = child_process.spawn('python.exe', ['script.py'])
// check if process is still running
assert(child.kill(0) == true)
// to terminate gracefully, write newline to stdin
child.stdin.write('\n')
// check if process terminated itself
assert(child.kill(0) == false)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接