CodePark/ questions / Signals & process lifecycle
START PRACTICINGPRACTICE
Backend question · OS, networking & Linux › Signals & process lifecycle

A script start.sh launches Node as its last line. You run kill <pid of start.sh>. The script exits, but Node keeps running and holding the port. Why, and how do you fix it?

#!/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.