What is the proper way for supervisord to reliably restart the npm start command?

I have initiated the “npm start” command using supervisord. However, I’ve encountered a situation where stopping or rebooting supervisord leaves the node app.js process running without termination. How can I ensure that supervisord properly restarts the npm start command under these circumstances?

Here is my supervisord.conf configuration:

[supervisord]
nodaemon=true

[program:my_node]
command=npm start
directory=/xx
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
user=root
autostart=true
autorestart=true
redirect_stderr=true
exitcodes=1

And here is the relevant part of my package.json:

{
  "name": "xx",
  "version": "1.0.0",
  "main": "app.js",
  "scripts": {
    "start": "node app.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "xxx"
  },
  "devDependencies": {
    "nodemon": "^1.11.0"
  },
  "description": ""
}

Ensure supervisord kills the old Node.js process and manages restarts properly:

  1. Use a PID file: Include a pidfile in your config to track processes effectively.
  2. [program:my_node]
    command=npm start
    directory=/xx
    pidfile=/tmp/my_node.pid
    stdout_logfile=/dev/stdout
    stderr_logfile=/dev/stderr
    user=root
    autostart=true
    autorestart=true
    redirect_stderr=true
    exitcodes=1
    
  3. Handle signals in Node.js app: Make sure your app can terminate on signals like SIGTERM and SIGINT.
  4. // In app.js
    process.on('SIGTERM', process.exit);
    process.on('SIGINT', process.exit);
    

These steps should prevent lingering processes and ensure reliable restarts.

Ensuring that supervisord reliably restarts your npm start command involves making sure the existing Node.js process is properly terminated before the new one starts. Here are some additional strategies you might consider adopting:

Additional Strategies

  1. Use the stopwaitsecs Option: This option specifies the wait time for a program to shutdown via the TERM signal before using the KILL signal. By lengthening this duration, you can allow your Node.js process more time to complete shutdown processes.
    <pre><code>[program:my_node]
    

    command=npm start
    directory=/xx
    stopwaitsecs=10
    pidfile=/tmp/my_node.pid
    stdout_logfile=/dev/stdout
    stderr_logfile=/dev/stderr
    user=root
    autostart=true
    autorestart=true
    redirect_stderr=true
    exitcodes=1

  2. Implement Retry Mechanism: In scenarios where a Node.js script ends unexpectedly, use a retry logic within the script to attempt restarts automatically without needing a manual supervisord supervision to reset.
    <pre><code>// Retry Logic in node app.js
    

    function startApp() {
    try {
    // Your main logic
    } catch (e) {
    // handle error
    console.error(e);
    setTimeout(startApp, 5000); // Retry after 5 seconds
    }
    }

    startApp();

  3. Consider the process_control Option: Use this supervisord feature to configure how processes are controlled. Adjusting control methods can sometimes address issues with lingering processes.
    <pre><code>[program:my_node]
    

    command=npm start
    directory=/xx
    process_name=%(program_name)s
    stdout_logfile=/dev/stdout
    stderr_logfile=/dev/stderr
    user=root
    autostart=true
    autorestart=true
    redirect_stderr=true
    exitcodes=1
    process_control=True

Implementing these recommendations should further stabilize your supervisord configuration, providing a robust solution for managing your Node.js application lifecycle effectively.