You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

父进程触发SIGINT时,如何通过forever-monitor通知子进程?

解决方案:通过IPC通道实现父子进程优雅关闭

在Windows环境下,forever-monitor创建的子进程默认处于detached状态,常规的信号传递(比如SIGINT)可能无法直接触发子进程的优雅关闭逻辑。我们可以通过Node.js的IPC进程通信通道来实现父进程向子进程发送关闭指令,具体修改如下:

修改monitor.js(父进程)

我们需要开启IPC通道,并在收到退出信号时向子进程发送关闭指令,同时等待子进程完成关闭(或超时强制关闭):

const path = require('path');
const forever = require('forever-monitor');
let child;

function exit() {
  console.error('Received exit signal on main process.');
  if (!child) {
    process.exit(0);
    return;
  }

  // 向子进程发送优雅关闭指令
  child.send('shutdown');
  
  // 设置超时,防止子进程卡住无法退出
  const shutdownTimeout = setTimeout(() => {
    console.log('Child process did not shut down in time, force stopping...');
    child.stop();
    process.exit(0);
  }, 5000); // 5秒超时阈值可根据你的服务调整

  // 监听子进程退出事件,清除超时并正常退出父进程
  child.once('exit', () => {
    clearTimeout(shutdownTimeout);
    console.log('Child process exited, shutting down main process.');
    process.exit(0);
  });
}

// Windows下SIGKILL无法被捕获,因此移除该监听
['SIGINT', 'SIGTERM'].forEach(signal => process.on(signal, exit));

// 创建Monitor实例时开启IPC通道
child = new forever.Monitor(path.join(__dirname, 'server.js'), {
  stdio: ['inherit', 'inherit', 'inherit', 'ipc'] // 前三个参数继承父进程的IO,第四个开启IPC
});

child.start();

修改server.js(子进程)

我们需要监听来自父进程的IPC消息,收到关闭指令时调用stopServer函数,同时处理自身的信号监听(确保子进程单独运行时也能优雅关闭):

const express = require('express');
const app = express();
const port = process.env.PORT || 8080;
let server;

function stopServer(callback) {
  if (!server) {
    callback?.(null);
    process.exit(0);
    return;
  }

  console.log('Shutting down server gracefully...');
  server.close((err) => {
    if (err) {
      console.error('Failed to shut down server:', err);
      callback?.(err);
      process.exit(1);
    } else {
      console.log('Server shut down successfully.');
      // 如果是子进程,通知父进程关闭完成
      if (process.send) {
        process.send('shutdown-complete');
      }
      callback?.(null);
      process.exit(0);
    }
  });
}

// 监听父进程发送的IPC消息
process.on('message', (msg) => {
  if (msg === 'shutdown') {
    stopServer();
  }
});

// 监听子进程自身的退出信号(比如单独运行时的Ctrl+C)
['SIGINT', 'SIGTERM'].forEach(signal => {
  process.on(signal, () => {
    stopServer();
  });
});

app.get('/', (request, response) => response.send('Hello'));

server = app.listen(port, () => console.log(`Server is running on port "${port}".`));

关键说明:

  1. IPC通道的必要性:在Windows的detached子进程场景下,信号传递机制有限,IPC是跨平台且可靠的进程通信方式,能确保父进程的关闭指令准确传递到子进程。
  2. 超时保护:添加超时逻辑是为了避免子进程因某些异常无法关闭,导致父进程一直挂起。
  3. 双向兼容:给子进程也添加自身的信号监听,确保无论子进程是被forever-monitor管理还是单独运行,都能优雅关闭。

内容的提问来源于stack exchange,提问作者Benny Neugebauer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:00:42