Nodemon: Nodemon is not able to gracefully restart applications under Windows

Created on 9 May 2019  路  16Comments  路  Source: remy/nodemon

  • nodemon -v: any
  • Operating system/terminal environment: Windows 10 Build 1809

Expected behaviour

Restarts while watching should send some kind of signal to the child processes so they can perform graceful restarts (and clean up resources) similar to listening to SIGINT signals.

Actual behaviour

On Windows this is not hapenning right now. On a file change the node process is forcefully killed without the possibility to perform cleanup tasks.

This is happening because nodemon is using a forced taskkill call on Windows:

https://github.com/remy/nodemon/blob/d088cb6e66855bbed04511c15fa12de0f8829237/lib/monitor/run.js#L334

After experimenting a bit I was able to come up with an experimental solution which has its flaws. Replacing the exec call with child.send("SIGUSR2") for IPC messaging allowed me to add a process.on("message", (message) => { if (message === "SIGUSR2") { process.kill(process.pid); } }) which was invoked properly, however it MUST end in process.kill(process.pid) otherwise nodemon will hang. Surprisingly enough this worked in my short tests and most likely will be my custom solution for this.

One big caveat is of course that the child process MUST kill itself properly. Furthermore I can't predict what will happen on long-running cleanup processes.

I'd like to discuss whether you'd be interested in having such an experimental SIGUSR2-signal (which is not an actual signal but an IPC message) for Windows as an optional feature using another config option that replaces the hard taskkill. I can create a PR if you're not going to implement it yourself.

stale

All 16 comments

Further information: I just realized this only works when the child processes are forked and spawned. There is a weird check whether --inspect is the first argument, if so spawn is forced not allowing IPC unforunately. Whats the problem with --inspect and fork?

A bit of context: originally nodemon used spawn all the time, but there were problems with sub process exit, namely the sub process would be left running in particular situations.

So fork was added if it's a node process (since it can fork the native process, as opposed to something like python).

We can't fork when the node exec arguments change however (or that I'm aware of after neatly a decade of nodemon). Specifically, if your sub process wants to run with --inspect then nodemon has to spawn the process (rather than fork) because nodemon itself wasn't started under a node --inspect session.

As for Windows, I've got limited access myself (typically running a VM, which is not a smooth workflow in the slightest), so I'd be happy to look at a PR, or maybe discuss your idea here in a little more detail (I'm replying on my phone ATM at 8am, so not quite grokked the gist of what you're hitting!)

Alright, I have a bunch of information, insights and ideas I want to share in no particular order that came up during my research and experiments with the nodemon code.

  • My initial intention was to facilitate the ability to notify the child process about a restart in order to allow for some cleanup routines. Turns out this isn't possible with spawned processes, only with forked ones since my approach relies on IPC.
  • Naively I expected to be able to force nodemon to fork the processes all the time. In fact it actually worked at one point where child processes would be executed via fork and receive a signal for SIGUSR2 over the IPC channel so that applications on Windows can handle them as well.
  • Forking, compared to spawning, discards the --inspect option that I wanted to carry over of course. Manually enforcing --inspect as one execArgv actually worked which could've been toggled using an option. At this point I noticed that the sample repo from the other issue is running nodemon --inspect index.js which is semantically something different altogether. I do not want to debug the nodemon process, even though the (VSCode) debugger attaches to spawned child processes neatly.
  • On top of that debugging in restarted processes happens to behave weird since the debugger attaches too late. Don't ask my why this happens.
  • Furthermore I recognized semantical issue when running nodemon on a single file that gets interpreted by node or when running an entirely different command. In my personal project I have an exec option so that nodemon executes node --inspect -r ts-node/register -r tsconfig-paths/register src/index.ts. Analyzing whether to fork or spawn the process in this case is pretty cumbersome to say the least.

What it really comes down to is most likely a completely different way of handling this since changing anything is definitely going to cause even more side-effects I cannot even fathom. I was even considering something as simple as a file called .restart that the application itself can watch for using fs.watch and trigger cleanup and deletion of the file once nodemon writes it.

Quick update once again with regards to the idea with the .restart file. I was successfully able to implement this method and can confirm that this works in my use case. Basically instead of the exec('taskkill /pid ' + child.pid + ' /T /F') call nodemon now calls writeFileSync(".restart", undefined) if the flag is enabled and does not kill the child itself.

In my child process I have the following snippet:

const restartFile = path.join(process.cwd(), ".restart");
chokidar.watch(restartFile).on("add", () => {
    // tslint:disable-next-line: non-literal-fs-path
    fs.unlinkSync(restartFile);
    /* cleanup */
    process.exit(0);
});

One could consider creating a small package out of this snippet to simplify its usage to something like:

registerNodemonListener(() => {
    /* cleanup */
});

Another alternative that comes to my mind is the creation of a simple TCP server in the application just listening for a single incoming message and opening a connection from nodemon once a restart should be initiated. This alleviates the issue of cluttering the file system and inclusion of chokidar as a third party library however it can of course be an issue if the server-side snippet in the application itself it not removed/pruned during production builds.

This issue has been automatically marked as idle and stale because it hasn't had any recent activity. It will be automtically closed if no further activity occurs. If you think this is wrong, or the problem still persists, just pop a reply in the comments and @remy will (try!) to follow up.
Thank you for contributing <3

bump, a solution would be great.

This issue has been automatically marked as idle and stale because it hasn't had any recent activity. It will be automtically closed if no further activity occurs. If you think this is wrong, or the problem still persists, just pop a reply in the comments and @remy will (try!) to follow up.
Thank you for contributing <3

Same issue here, so bump

Nodemon just hangs after logging this:
[nodemon] restarting due to changes...

I issue a SIGINT (Control+C), but the process is still running, and I need to kill the process manually.

+1 for this issue.

My current workaround is to use nodemon through the Windows Subsystem for Linux. Works with the --inspect flag too.

This issue has been automatically marked as idle and stale because it hasn't had any recent activity. It will be automtically closed if no further activity occurs. If you think this is wrong, or the problem still persists, just pop a reply in the comments and @remy will (try!) to follow up.
Thank you for contributing <3

+1 to keep this alive

+1 Please

+1

+1

Those "plus'ing 1" are

  • commenting on a closed issue
  • commenting on an issue that was created 12 months ago and the code has changed
  • are not contributing anything useful at all - in fact, github has their own UI for this
  • are not providing example code to reproduce or actual help others to solve the issue.
Was this page helpful?
0 / 5 - 0 ratings

Related issues

robboerman picture robboerman  路  3Comments

endquote picture endquote  路  4Comments

Mohammad-Quanit picture Mohammad-Quanit  路  5Comments

medoix picture medoix  路  4Comments

giacomorebonato picture giacomorebonato  路  5Comments