node.jssupervisordnuxt3.js

Nuxt 3 server does not stop when restarting supervisor job


I have set up a production environment for a nuxt app where the nuxt server gets run through a supervisor job. When the port is not in use this works well. However, if I issue the supervisorctl reload or supervisorctl restart production-frontend commands the previous nuxt server usually fails to exit. This means that when it tries to start the nuxt server again it errors out.

Is there a special trick to get nuxt to work nicely with supervisor or a parameter I can add to the supervisor process so the nuxt server guaranteed shuts down when I restart it? I would rather not have to resort to giving the deploy process the power to kill any previous process that still may be lingering through kill -9 like I now have to do manually.

This is the content of /etc/supervisor/conf.d/production-frontend.conf

[program:production-frontend]
command=/usr/bin/npm start
directory=/var/www/production/frontend
environment=NODE_ENV="production",PORT="3011"
autostart=true
autorestart=true
startretries=10
startsecs=30
user=www-data
stderr_logfile=/var/log/supervisor/production-frontend_error.log
stdout_logfile=/var/log/supervisor/production-frontend_out.log

/var/www/production/frontend contains the .output folder from a npm run build command and a package.json file. npm run start will start the nuxt server with node .output/server/index.mjs.

Whenever the server fails to start the error log shows the following error message:

[nitro] [dev] [uncaughtException] Error: listen EADDRINUSE: address already in use :::3011

Running netstat -pln | grep 3011 shows a still running nuxt server.


Solution

  • As it turns out npm start will run a command

    sh -c -- node .output/server/index.mjs
    

    This in turn will start a process

    node .output/server/index.mjs
    

    This can be verified with in a shell with the following commands. Note that 191667 is the parent (sh) and 191668 is the nuxt server.

    $ netstat -pln | grep 3301
    tcp6       0      0 :::3011                 :::*                    LISTEN      191668/node
    $ pstree -p 191668
    sh(191667)───node(191668)─┬─{node}(191669)
                              ├─{node}(191670)
                              ├─{node}(191671)
                              ├─{node}(191672)
                              ├─{node}(191673)
                              ├─{node}(191674)
                              ├─{node}(191675)
                              ├─{node}(191676)
                              ├─{node}(191677)
                              └─{node}(191678)
    

    Supervisor will kill the parent process, but not the child process. Instead just run the command directly. In my case running node .output/server.index.mjs is fine. If something is not installed globally you might need to define the entire path to whatever you are trying to run (e.g. ./node_modules/jest/bin/jest this_makes_no_sense_for_supervisor.