nodemon: Nodemon is not able to gracefully restart applications in Windows environment

Possibly related to https://github.com/remy/nodemon/issues/1567

  • nodemon -v: 6.13.4

  • node -v: v12.16.1

  • Operating system/terminal environment:

    • Windows Command Prompt, Windows Git Bash, Windows Terminal WSL
         Edition: Windows 10 Pro 
         Version: 1909
    Installed on: 5/22/2019
        OS Build: 18363.836 
    
  • Command ran: nodemon --signal SIGHUP index.js

Expected behaviour

On Windows, Nodemon should wait for the process to complete if it handles a shut down signal.

Notice the express server closed message

WSL: wsl

Actual behaviour

The application is killed and restarted right away. This behavior does not exist in Linux, Mac and WSL.

CMD: windows

Steps to reproduce

I have created a sample Express app here: https://github.com/chriswoodle/nodemon-1567 that shuts down the express server once the application is signaled to stop ['SIGTERM', 'SIGINT', 'SIGHUP']

git clone https://github.com/chriswoodle/nodemon-1567.git
cd nodemon-1567
npm install
npm start
touch index.js

Let me know if I can provide any more information or test changes, thanks.


About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 11
  • Comments: 50 (24 by maintainers)

Commits related to this issue

Most upvoted comments

If I get time, I’ll look into this, but I wanted to stop and say:

Thank you for filing an issue with a good level of detail and a good example of pared down code to replicate the issue. I’ll be pointing people to this issue as an example of what makes the world of difference in debugging. 🙏

Still isn’t resolved

Merged and live.

Yep, I’ve opened a new issue: https://github.com/remy/nodemon/issues/1866

@countzero 's repo seems to work just fine.

@wrexbe @chriswoodle @cowboyd @nicholas-ochoa @JulianNicholls @usm076 @caesay @oviecodes @GIDustin @sridharjatla Do you have some time to test this solution to our shared problem?

You can simply check out https://github.com/countzero/nodemon_windows_kill to rapidly test this fix.

The SIGINT behaviour can be tested with:

npm run watch-graceful-shutdown

And the “old” SIGKILL behaviour with:

npm run watch-hard-shutdown

See https://github.com/countzero/nodemon_windows_kill/blob/main/package.json for technical details.

@remy I am not quite sure what else can be done here. What are the next steps?

2.0.8-alpha.a is correctly shutting down, and restarting for me.

It might help if ‘SIGKILL’ mapped to the previous method, to give people another option if the program they are working on ignores SIGINT, or just takes a long time, and they don’t care about it safely exiting.

Folks, there’s a debug build available on npm from @countzero’s great work.

Those with Windows, could you test the install using npm i -g nodemon@debug which should give you 2.0.8-alpha.a - and then check that it shuts the windows sub-process down correctly.

If you can comment here or on PR #1853 that would be perfect to help sign these changes off.

Here is a way to send ctrl-c to the node process.

Command

powershell.exe -nologo -noprofile -executionpolicy bypass .\ctrlc.ps1 ProcessIdHere

File: ctrlc.ps1

Add-Type -Names 'w' -Name 'k' -M @(
    '[DllImport("kernel32.dll")] public static extern bool FreeConsole();',
    '[DllImport("kernel32.dll")] public static extern bool AttachConsole(uint p);',
    '[DllImport("kernel32.dll")] public static extern bool GenerateConsoleCtrlEvent(uint e, uint p);'
)
If ([w.k]::FreeConsole()) {
    If([w.k]::AttachConsole($args[0])) {
        If([w.k]::GenerateConsoleCtrlEvent(0, 0)){
            exit 0
        }
    }
}
throw;

Edit:

Made it so I didn’t need a separate file. This approach doesn’t work though. It sends the Ctrl-C to too many things.

const pid = 2500;
const ctrlcScript = Buffer.from(\`Add-Type -Names 'w' -Name 'k' -M @(
    '[DllImport("kernel32.dll")] public static extern bool FreeConsole();',
    '[DllImport("kernel32.dll")] public static extern bool AttachConsole(uint p);',
    '[DllImport("kernel32.dll")] public static extern bool GenerateConsoleCtrlEvent(uint e, uint p);'
);
If ([w.k]::FreeConsole()) {
    If([w.k]::AttachConsole(${pid})) {
        If([w.k]::GenerateConsoleCtrlEvent(0, 0)){
            exit 0;
        }
    }
}
exit 1;`.replace(/(\r\n|\n|\r)/gm, " "), 'utf16le').toString('base64');
var cp = require('child_process');
cp.exec(`powershell.exe -nologo -noprofile -executionpolicy bypass -EncodedCommand ${ctrlcScript}\`, function(e, stdout, stderr) {
  console.log(stdout);
  console.log(stderr);
});

fyi, we wrote a very small package to do nothing except send a CTRL_C event to a windows process to handle situations exactly like this. https://github.com/thefrontside/ctrlc-windows/

Don’t know if it would be a handy thing to use here, but it’s worked well for us, and is extremely lightweight.

Just bumping this because of the message from the bot and this does not appear to be resolved as of yet. Ideally nodemon should send a signal and wait for the process to exit before restarting and it does not currently do this.

To clarify on the “Terminate batch job (Y/N)?” question, it’s true that this only happens with a batch/cmd file which is executed directly from terminal. For example, upon Ctrl-C:

  • node index.js no prompt
  • nodemon index.js (installed with -g) prompt present
  • npm run nodemon-pkg-script (installed locally as dev-dep) prompt present
  • node "node_modules/nodemon/bin/nodemon.js" no prompt

Additionally, I do not believe you need a third party binary to do this if you are happy to use powershell, the following line of powershell will give you a list of all of the processes running, their pid, and their parent pid - so from here it would be possible to terminate a process tree recursively with no additional binaries:

gwmi win32_process | select -property Name,ProcessId,ParentProcessId