【问题标题】:What is the Windows equivalent of process.on('SIGINT') in node.js?node.js 中 process.on('SIGINT') 的 Windows 等效项是什么?
【发布时间】:2023-03-31 08:13:01
【问题描述】:

我正在按照指导 here(监听 SIGINT 事件)正常关闭我的 Windows-8 托管的 node.js 应用程序以响应 Ctrl+C 或服务器关闭。

但是 Windows 没有SIGINT。我也尝试过process.on('exit'),但这似乎已经晚了。

在 Windows 上,这段代码给了我:错误:没有这样的模块

process.on( 'SIGINT', function() {
  console.log( "\ngracefully shutting down from  SIGINT (Crtl-C)" )
  // wish this worked on Windows
  process.exit( )
})

在 Windows 上,这段代码可以运行,但是来不及做任何优雅的事情

process.on( 'exit', function() {
  console.log( "never see this log message" )
})

Windows 上是否有 SIGINT 等效事件?

【问题讨论】:

  • 这个问题今天随机出现在我身上,我认为它与readline模块本身有关。我无法进行任何测试,但自从我添加了这个模块后,我就开始遇到问题了。

标签: windows node.js


【解决方案1】:

Windows + Git Bash/Cygwin 解决方案:

Windows 和 Git Bash 的其他解决方案都不起作用,所以我的解决方案是简单地使用 WINPTY 来启动 Node:

我的package.json 有这个启动脚本:

"start": "winpty node app.js"

这受到此处接受的类似 Python 问题的答案的启发:

python error Suppressing signal 18 to win32

注意:WINPTY 在 Windows XP 及更高版本上运行。

【讨论】:

    【解决方案2】:

    上面没有对我有用,所以解决方法是挂一个 readline 并从那里捕获信号。

    这是我的解决方案:

    const readline = require('readline');
    
    const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
    
    // Flag to be able to force the shutdown
    let isShuttingDown = false;
    
    // https://nodejs.org/api/readline.html
    rl.on('SIGINT', async () => {
      if (isShuttingDown) {
        logger.info("Forcing shutdown, bye.");
        process.exit();
      } else {
        if (!<yourIsCleanupNecessaryCheck>()) {
          logger.info("No cleanup necessary, bye.");
          process.exit();
        } else {
          logger.info("Closing all opened pages in three seconds (press Ctrl+C again to quit immediately and keep the pages opened) ...");
          isShuttingDown = true;
          await sleep(3000);
          await <yourCleanupLogic>();
          logger.info("All pages closed, bye.");
          process.exit();
        }
      }
    
    function sleep(ms: number) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }
    

    它非常普通,它是异步的,并且可以在 MacOS 11.3 和 Windows 10 上运行(在撰写本文时)。

    【讨论】:

      【解决方案3】:

      我不确定何时开始,但在节点 8.x 和 Windows 10 上,原始问题代码现在可以正常工作。

      process.on( "SIGINT", function() {
        console.log( "\ngracefully shutting down from SIGINT (Crtl-C)" );
        process.exit();
      } );
      
      process.on( "exit", function() {
        console.log( "never see this log message" );
      } );
      
      setInterval( () => console.log( "tick" ), 2500 );
      

      也适用于 Windows 命令提示符。

      【讨论】:

      • 我也注意到了这一点。 Windows 7 对我来说是一个主要问题
      • 此方法适用于 Windows 7 上的 Node 8.11.1 - 我是从 git bash shell 运行它。以为我会先尝试简单的方法,它奏效了。
      • 在 git bash 窗口上不起作用
      【解决方案4】:

      现在 它可以正常工作 on all platforms,包括 Windows。

      以下代码记录,然后在 Windows 10 上正确终止:

      process.on('SIGINT', () => {
          console.log("Terminating...");
          process.exit(0);
      });
      

      【讨论】:

      • 这对我在 cygwin 下不起作用。使用最新的 Windows 10(自动更新),节点版本 8.11.4。 “它不起作用”是指 1) 进程确实终止了,但是 2) 消息没有记录到控制台,并且 3) 创建的 HTTP 连接没有关闭。但是,我应该补充一点,我在 PowerShell 下尝试过它,它在那里按预期工作。但我切换到 cygwin 是因为 PowerShell 的 curl 命令不好。该死!
      • 它今天停止为我工作,没有明显的原因(根本没有更新),我仍然不知道为什么。接受的答案修复了它。
      • git bash 窗口不起作用
      【解决方案5】:

      除非您需要为其他任务导入“readline”,否则我建议在程序验证它在 Windows 上运行后导入“readline”。此外,对于那些可能不知道的人 - 这适用于 Windows 32 位和 Windows 64 位系统(将返回关键字“win32”)。感谢加布里埃尔的这个解决方案。

      if (process.platform === "win32") {
        require("readline")
          .createInterface({
            input: process.stdin,
            output: process.stdout
          })
          .on("SIGINT", function () {
            process.emit("SIGINT");
          });
      }
      
      process.on("SIGINT", function () {
        // graceful shutdown
        process.exit();
      });
      

      【讨论】:

        【解决方案6】:

        您必须使用 readline 模块并监听 SIGINT 事件:

        http://nodejs.org/api/readline.html#readline_event_sigint

        if (process.platform === "win32") {
          var rl = require("readline").createInterface({
            input: process.stdin,
            output: process.stdout
          });
        
          rl.on("SIGINT", function () {
            process.emit("SIGINT");
          });
        }
        
        process.on("SIGINT", function () {
          //graceful shutdown
          process.exit();
        });
        

        【讨论】:

        • 这太荒谬了。为什么节点核心不处理这个?
        • 因为当您收听标准输入时,除非您明确发送 SIGINT 信号,否则该过程永远不会结束。
        • 如何在 Windows 上向子进程发送 SIGINT?即使使用 readline,我的 child.kill('SIGINT') 似乎也不起作用。
        • 因此,需要从父节点向子节点发送随机消息,例如:“SIGINT”。
        • 看起来这个问题很久以前就解决了:github.com/nodejs/node-v0.x-archive/issues/5054
        【解决方案7】:

        从 node.js 0.8 开始,keypress 事件不再存在。然而,有一个名为 keypress 的 npm 包重新实现了该事件。

        使用npm install keypress 安装,然后执行以下操作:

        // Windows doesn't use POSIX signals
        if (process.platform === "win32") {
            const keypress = require("keypress");
            keypress(process.stdin);
            process.stdin.resume();
            process.stdin.setRawMode(true);
            process.stdin.setEncoding("utf8");
            process.stdin.on("keypress", function(char, key) {
                if (key && key.ctrl && key.name == "c") {
                    // Behave like a SIGUSR2
                    process.emit("SIGUSR2");
                } else if (key && key.ctrl && key.name == "r") {
                    // Behave like a SIGHUP
                    process.emit("SIGHUP");
                }
            });
        }
        

        【讨论】:

          【解决方案8】:

          目前 node 中仍然不支持捕获 windows 控制台控制事件,因此没有 POSIX 信号的等效项:

          https://github.com/joyent/node/issues/1553

          但是tty module documentation 确实提供了一个捕获按键以启动正常关机的机制示例,但这仅适用于 ctrl+c kbd>.

          var tty = require('tty');
          
          process.stdin.resume();
          tty.setRawMode(true);
          
          process.stdin.on('keypress', function(char, key) {
            if (key && key.ctrl && key.name == 'c') {
              console.log('graceful exit of process %d', process.pid);
              process.exit();
            }
          });
          

          【讨论】:

          • 谢谢,一直在寻找这个信息,这对我来说是一个可以接受的替代品,只要我可以在服务器上为 CTRL+C 实现它。 +1(但是..知道这是否会通过在进程上添加事件侦听器来影响性能?)
          • 我试过这样做,但是当我的服务器运行游戏循环时,stdin 似乎不可用,当我使用上述方法时,CTRL+C 不起作用。
          猜你喜欢
          • 2012-12-27
          • 2011-12-02
          • 2011-02-10
          • 2021-08-07
          • 2011-10-16
          • 2011-03-19
          • 2012-08-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多