Nodemon: Nodemon process started from tmux resists death

Created on 4 Mar 2018  路  7Comments  路  Source: remy/nodemon

When I start nodemon within a tmux session on macOS, the nodemon process lives on after the tmux session has been killed. I can't get nodemon to die unless I specifically kill it.

I'd instead like to persuade nodemon to die like other processes do when the tmux window they started from is killed.

I'm using nodemon v1.71.1, node v9.5.0, tmux 2.6, and macOS 10.13.3.

Here's an example:

Start a tmux session (no config file presumed, just using the out-of-box settings):

tmux

Create a sample project, and install nodemon locally:

$ mkdir test; cd test; npm init --yes
$ echo "console.log('hello world')" > index.js
$ npm install -D nodemon

Start nodemon and note the parent PID:

$ ./node_modules/.bin/nodemon --verbose

In a separate terminal, verify the parent PID shows up in ps:

$ ps x | grep nodemon

In my case I see:

 8643 s002  S+     0:00.44 node ./node_modules/.bin/nodemon --verbose

Kill the tmux window running nodemon. Since there is only one window, the tmux session will also end:

C-b : kill-window

Finally, re-run the ps command. When I do that, the nodemon process is still there, now in limbo since its controlling terminal is gone:

8643   ??  S      0:00.45 node ./node_modules/.bin/nodemon --verbose

I'm not sure whether tmux is doing something nodemon doesn't expect, or the other way around. I can't replicate the issue under Linux.

help wanted

Most helpful comment

Can you try running nodemon with the following:

nodemon --signal SIGHUP

This tells nodemon to use SIGHUP to restart your child process, but in addition, it listens for SIGHUP2 to trigger restarts - which, _might_ circumvent the issue you're seeing.

All 7 comments

I'm not entirely familiar with the inner workings of tmux, but do you know what kill signal tmux uses to end the child processes when it closes?

I think it's SIGHUP, based on a casual looking-around, but I claim no particular authority on that.

I did come across a similar discussion which suggests this behavior isn't unique to nodemon.

I'd like to subtract tmux from the equation, however, because I can replicate the behavior without it. If I launch nodemon in a plain macOS terminal and then close the window (which is more-or-less what tmux would do), the nodemon process lives on in the detached state described previously.

Would it be possible for nodemon to distinguish SIGHUPs meant to trigger restart from SIGHUPs meant to terminate for good by checking for a controlling terminal?

A SIGHUP (as far as I understand) is simply a single int signal to the process, so no, I don't think there's a way to distinguish.

Nodemon does actually trap SIGHUP to tell the child process to restart, so I suspect that's why nodemon is still running after tmux ends.

If you run a daemon process in tmux (that would restart with a SIGHUP) how would the process know to end when the tmux session starts? (real question, wondering if it's possible to get some ideas from prior art).

Oh wait, I misread your part about running without tmux.

I'm pretty sure, if the process is still attached to the session, if you close s terminal session, it'll send a SIGTERM - I'd like to double check this on my own machine tomorrow but I'm 99% sure that's the case which might mean there's something else at play here.

I took a closer look at the signal that is sent when the terminal session closes, and it turned out to be SIGHUP rather than SIGTERM.

I used the kill.d utility, which uses DTrace and available by default on macOS as far as I can tell. With that running in one session and nodemon running in a second session, closing the terminal window registers as a HUP and not a TERM. If I send a TERM from a third window via kill -TERM [nodemon parent pid] then nodemon dies as intended.

No answers, unfortunately, just a reframing of the issue. As you mentioned earlier, the trapping of SIGHUP is the trouble. If it is used to tell the child process to restart, in a daemon-ish sort of way, there is an implied expectation that it won't also be used to tell the parent process to shut down. But it is.

Can you try running nodemon with the following:

nodemon --signal SIGHUP

This tells nodemon to use SIGHUP to restart your child process, but in addition, it listens for SIGHUP2 to trigger restarts - which, _might_ circumvent the issue you're seeing.

Listening for SIGHUP2 has resolved the problem. Use of the --signal argument has allowed the nodemon parent process to fully exit when intended, both for the with-tmux and without-tmux scenarios.

Thanks for the help.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Exeteres picture Exeteres  路  4Comments

Mohammad-Quanit picture Mohammad-Quanit  路  5Comments

endquote picture endquote  路  4Comments

ehmicky picture ehmicky  路  4Comments

giacomorebonato picture giacomorebonato  路  5Comments