nodemon icon indicating copy to clipboard operation
nodemon copied to clipboard

feat: improve signal handling with timeout and better POSIX compliance (#1705)

Open harshcoder-harsh opened this issue 1 month ago • 2 comments

Description

Implements the signal handling improvements proposed in #1705 for better POSIX compliance and systemd compatibility.

Changes

  • SIGINT: Graceful shutdown with double Ctrl+C for force quit
  • SIGTERM: Graceful shutdown with timeout, then SIGKILL (systemd-compatible)
  • SIGQUIT: Immediate termination without cleanup
  • SIGHUP: Default reload signal (replaces SIGUSR2)
  • ⚙️ killTimeout: Configurable timeout for graceful shutdown (default: 10s)
  • 📝 Documentation: Updated README with signal handling behavior and migration notes

Breaking Changes

⚠️ Default signal changed from SIGUSR2 to SIGHUP

Applications listening for SIGUSR2 should either:

  • Update code to listen for SIGHUP (recommended), or
  • Set --signal SIGUSR2 in nodemon configuration

Migration Example

// Old (still works with --signal SIGUSR2)
process.on('SIGUSR2', () => gracefulShutdown());

// New (recommended)
process.on('SIGHUP', () => gracefulShutdown());

Implementation Details

New killWithTimeout() Function

Added a new function that implements graceful shutdown with timeout-based escalation:

  • Sends initial signal to child process
  • Waits for configurable timeout
  • Escalates to SIGKILL if child doesn't exit gracefully
  • Properly manages event listeners and timers

Signal Handler Improvements

  1. SIGINT (Ctrl+C):

    • First press: Graceful shutdown with timeout
    • Second press: Immediate SIGKILL
    • Provides user control over shutdown behavior
  2. SIGTERM:

    • Passes signal to child
    • Waits for killTimeout
    • Escalates to SIGKILL if needed
    • Aligns with systemd's TimeoutStopSec
  3. SIGQUIT (new):

    • Immediate SIGKILL
    • No cleanup
    • For emergency scenarios
  4. SIGHUP (new):

    • Default reload signal
    • Replaces SIGUSR2 for better POSIX compliance

Testing

Manual testing has been performed for:

  • ✅ SIGINT single press (graceful exit)
  • ✅ SIGINT double press (force quit)
  • ✅ SIGTERM with graceful exit
  • ✅ SIGTERM with timeout escalation
  • ✅ SIGQUIT immediate termination
  • ✅ SIGHUP reload
  • ✅ Custom killTimeout configuration

Backward Compatibility

Users can maintain the old behavior by explicitly setting signal: 'SIGUSR2' in their configuration:

nodemon --signal SIGUSR2 server.js

Or in nodemon.json:

{
  \"signal\": \"SIGUSR2\"
}

Related Issues

Fixes #1705 Related to #1667, #1661

Checklist

  • [x] Code follows the project's coding standards
  • [x] Documentation updated
  • [x] Breaking changes documented
  • [x] Commit messages follow conventional commits format
  • [x] Changes are backward compatible (with configuration)

harshcoder-harsh avatar Dec 03 '25 19:12 harshcoder-harsh

Deploy Preview for nodemon ready!

Name Link
Latest commit a9b6b75a1e1f054a860ae2546ed07bd33d787830
Latest deploy log https://app.netlify.com/projects/nodemon/deploys/69308f99b84af90008aeba6c
Deploy Preview https://deploy-preview-2263--nodemon.netlify.app
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

netlify[bot] avatar Dec 03 '25 19:12 netlify[bot]

There's no tests for this, but more worryingly, you've changed the defaults which would apply a massive blanket change.

I've not really read the AI generated PR description, happy if you want to write your own or summarise it down to a few lines with AI, but I do expect it to be fully tested.

One final point, there's no need for the details that were added to the readme, it's inconsistent with the project style.

remy avatar Dec 03 '25 20:12 remy