Что такое Windows-эквивалент process.on ('SIGINT') в node.js?

Я следую указаниям здесь (прослушивание SIGINT событий), чтобы корректно завершить работу моего приложения node.js, размещенного в Windows-8, в ответ на 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" )
})

Есть ли SIGINT эквивалентное событие в Windows?


person pappadog    schedule 05.04.2012    source источник
comment
Эта проблема случайно возникла у меня сегодня, и я думаю, что она как-то связана с самим модулем readline. Я не мог провести никакого тестирования, но с тех пор, как я добавил этот модуль, у меня начались проблемы.   -  person Sv443    schedule 01.02.2019


Ответы (7)


Вы должны использовать модуль 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();
});
person Gabriel Llamas    schedule 13.02.2013
comment
отличное обновление, спасибо! установка этого в качестве ответа, поскольку предыдущий ответ (прослушивание нажатия клавиш) больше не работает. - person pappadog; 16.02.2013
comment
Это смешно. Почему это не обрабатывается ядром узла? - person balupton; 19.11.2013
comment
Потому что, когда вы слушаете stdin, процесс никогда не завершается, пока вы явно не отправите сигнал SIGINT. - person Gabriel Llamas; 05.12.2013
comment
Как отправить SIGINT дочернему процессу в Windows? Мой child.kill ('SIGINT'), похоже, не работает даже с readline. - person Nick Sotiros; 17.05.2014
comment
Windows не имеет сигналов, вы не можете отправить SIGINT дочернему процессу. Главный процесс заключается в том, кто может прослушивать стандартный ввод, и именно так вы можете имитировать SIGINT в Windows, а дочерние процессы - нет. - person Gabriel Llamas; 18.05.2014
comment
Следовательно, вам необходимо отправить случайное сообщение от родителя к потомку, например: SIGINT. - person Gabriel Llamas; 18.05.2014
comment
@GabrielLlamas это не может перехватить process.kill(pid, 'SIGINT'), правда? - person Andy; 29.10.2016
comment
Просто окна вещи - person Luca Steeb; 04.01.2017
comment
Спасибо вам большое за это! Эта проблема сводила меня с ума! - person Derik Taylor; 17.03.2017
comment
Похоже, это было решено довольно давно: github.com/nodejs/ node -v0.x-archive / issues / 5054 - person SimonSimCity; 20.11.2017
comment
Похоже, это не работает из командной строки Windows Powershell. - person John Mills; 11.02.2021

Я не уверен, когда именно, но на узле 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.

person Meirion Hughes    schedule 28.07.2017
comment
Я тоже это заметил. Windows 7 является для меня серьезной проблемой - person Gregory Nowakowski; 29.08.2017
comment
Этот метод у меня работает с Node 8.11.1 в Windows 7 - но я запускал его из оболочки git bash. Подумал, что сначала попробую простой способ, и это сработало. - person user944849; 27.04.2018

Если вам не нужен импорт «строки чтения» для других задач, я бы посоветовал импортировать «строку чтения» после того, как программа проверит, что она работает в Windows. Кроме того, для тех, кто может не знать - это работает как в 32-битных, так и в 64-битных системах Windows (при этом будет возвращено ключевое слово «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();
});
person tim-montague    schedule 07.09.2013

В настоящее время он просто работает на всех платформах, включая Windows.

Следующий код записывает, а затем корректно завершает работу в Windows 10:

process.on('SIGINT', () => {
    console.log("Terminating...");
    process.exit(0);
});
person Heinrich Ulbricht    schedule 19.01.2018
comment
У меня это НЕ работает под cygwin. Используется последняя версия Windows 10 (автоматические обновления), версия узла 8.11.4. Под этим НЕ работает, я имею в виду, что 1) процесс завершается, но 2) сообщение не регистрируется в консоли и 3) созданные HTTP-соединения не закрываются. Однако я должен добавить, что я пробовал это в PowerShell, и там он работает так, как ожидалось. Но я перешел на cygwin, потому что в PowerShell плохая команда curl. Штопать! - person John Deighan; 10.09.2018
comment
Он перестал работать у меня только сегодня без видимой причины (вообще без обновлений), и я до сих пор не знаю почему. Принятый ответ исправил это. - person Sv443; 01.02.2019

В настоящее время в узле по-прежнему нет поддержки для захвата событий управления консоли Windows, поэтому нет эквивалентов сигналам POSIX:

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

Однако в документации по tty-модулю есть пример механизма захвата нажатий клавиш для инициирования плавное завершение работы, но тогда это работает только для ctrl + c.

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();
  }
});
person Pero P.    schedule 05.04.2012
comment
Спасибо, искал эту информацию, это приемлемая замена для меня, если я могу реализовать ее на сервере для CTRL + C. +1 (Но .. Есть идеи, повлияет ли это на производительность, добавив в процесс слушателей событий?) - person Cory Gross; 29.07.2012
comment
Я пробовал это сделать, но когда на моем сервере запущен игровой цикл, stdin кажется недоступным, CTRL + C не работает, когда я использую вышеуказанное. - person Cory Gross; 29.07.2012

Начиная с node.js 0.8 событие keypress больше не существует. Однако существует пакет npm, называемый keypress, который повторно реализует событие.

Установите с помощью 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");
        }
    });
}
person mekwall    schedule 01.01.2013

Ничего из вышеперечисленного у меня не сработало, поэтому обходной путь заключался в том, чтобы висеть строка чтения и ловить сигнал оттуда.

Вот мое решение:

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 (на момент написания).

person pierpytom    schedule 17.05.2021