2

I want to run a Node.js server with daemontools on Debian (Jessie) but my script running under supervise is constantly restarted. This is the run script that I'm using (/etc/service/node/run):

#!/bin/bash
exec setuidgid nodeuser bash -c './node'

The script executes the following script as user nodeuser, where I load NVM, change into my code directory, and execute the Node.js server:

#!/bin/bash

# Load NVM because we are in a non-interactive shell
export NVM_DIR="/home/nodeuser/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

# Run server
cd /path/to/code
exec node server.js

When I start the service with sudo svc -u /etc/service/node, the process is restarted all the time and ps faux shows the following process hierarchy (the depth of the hierarchy is always changing):

/bin/sh /usr/bin/svscanboot /etc/service/
 \_ svscan /etc/service
     \_ supervise node
         \_ /bin/bash ./node
             \_ /bin/bash ./node
                 \_ /bin/bash ./node
                     \_ /bin/bash ./node
                         \_ /bin/bash ./node
                         |   \_ /bin/bash ./node
                         |       \_ /bin/bash ./node
                         |       |   \_ /bin/bash ./node
                         |       |       \_ /bin/bash ./node
                         |       \_ /bin/bash ./node
                         |           \_ tail -n1
                         \_ /bin/bash ./node
                             \_ tail -n1

Do you have an idea what's going on there? When I execute the script manually with ./run, the server starts as expected and shows its output in the console.

EDIT

I found out that the service works only after rebooting. Once I restart it with sudo svc -du /etc/service/node, it behaves like described above.

chrisklaussner
  • 317
  • 3
  • 11

1 Answers1

3

That script is wrong. The maxim with the daemontools family is that the program executed by ./run must be the service process itself, not its parent, grandparent, or other relative. Services are run, not spawned.

The use of exec on the final line is the right idea, but is ruined by the following use of an explicit bash -c. This is unnecessary anyway, given that the ./node script has a #!/bin/bash script interpreter specified and is (presumably) executable. Better

#!/bin/bash
exec setuidgid nodeuser ./node

This can of course be a nosh (from the eponymous toolset) or an execlineb script, because there's no real need for the heavyweight Bourne Again shell just to run one single setuidgid command. Thus:

#!/bin/nosh
setuidgid nodeuser
./node
or
#!/command/execlineb -P
s6-setuidgid nodeuser
./node

Then when the service manager comes to take the service down in response to svc -d, it sends the signal to the correct actual service process.

Further reading

himdel
  • 105
  • 1
JdeBP
  • 66,967
  • 12
  • 159
  • 343