#!/bin/sh
export NODE_ENV=production
node server.js
kill sends the signal to one process only: the shell. Its children don't get it. The shell dies from SIGTERM, but Node receives nothing. Node becomes an orphan (a process whose parent has died). PID 1 becomes its new parent, and Node keeps running.
Ctrl-C seems to work in a terminal for a different reason. The terminal sends SIGINT to the whole foreground process group (the set of processes started together by that command).
The simplest fix is exec node server.js. exec replaces the shell with Node inside the same process. So the PID you signal is Node itself, and its SIGTERM handler runs.
Other fixes:
- Signal the whole process group with
kill -TERM -- -<pgid>. - Make the script trap (catch) SIGTERM and forward it to the child's PID.
Service managers like systemd avoid the problem. They track every process in the service's cgroup (a group of processes the kernel tracks together) and signal all of them on stop.
- kill targets a single process, so its children don't get the signal.
- The child becomes an orphan and keeps running.
- Ctrl-C works because it signals the whole foreground process group.
- exec makes Node replace the shell, so Node receives signals directly.
- Other fixes: signal the process group, or trap the signal and forward it.