Start script in /etc/service (runit) is not working with daemon

6,602

Don't use forever.

It's dead easy. As you've already observed, forever is unnecessary here as runit already is a service manager, and is already starting and restarting your program.

As you've also already observed, there are a few rules for what run programs must do. They must not fork and exit the main program. The runit service manager, like most daemontools-family service managers (there being a whole family of softwares that all work like this), expects that the process running the run program is the dæmon. Not its parent. Not a brief fly-by-night that forks and exits. But the actual dæmon itself.

a simple run program

There are various scripting languages that make writing such run programs a doddle. Laurent Bercot's execline is one. My nosh program is another. Presuming that bin/www is the actual executable program for your dæmon, a nosh run script would look something like:

#!/bin/nosh
fdmove -c 2 1
chdir /src
bin/www

An execline script is similarly brief. But the shell script isn't that much longer. If your run program is a shell script, the thing to remember is to overlay the shell program with your dæmon program in the same process. The shell command for doing this is exec and a shell script thus looks something like:

#!/bin/sh -e
exec 2>&1
cd /src
exec bin/www

I strongly recommend that, if your program does not require superuser privileges, you execute it via the chpst program (and its -u option), so that it starts as a non-privileged user — for best results, one that is dedicated to this service.

Several people have collected and published suites of run programs, over the years, and most of the run programs are that short and simple. Since you have runit, you can start with Gerrit Pape's own collection of run programs.

starting and stopping dæmons

When it comes to starting and stopping the service, again most daemontools-family service managers need to be told to stop auto-restarting the service. They all come with a tool to do this. You just need to use it in your clean-shutdown script.

  • runit has the sv program: sv down /etc/service/MyApp
  • s6 has the s6-svc program: s6-svc -d /etc/service/MyApp
  • perp has the perpctl program: perpctl d /etc/service/MyApp
  • daemontools has the svc program: svc -d /etc/service/MyApp
  • daemontools-encore has the svc program: svc -d /etc/service/MyApp
  • nosh has the service-control program: service-control --down /etc/service/MyApp which is also aliased as svc: svc -d /etc/service/MyApp

I said that it was a family of toolsets. In fact, under the covers all of these tools are speaking mostly the same protocol.

This brings me to a larger point. All of these toolsets are not exclusive. Just because you have runit, that doesn't stop you from using execline if you want to. Or you can run a nosh script under s6's service manager.

logging

You've tried to write log files with forever. Again, don't use forever. This isn't the right way to go about logging with runit. Redirecting standard output and error directly to files makes your logs impossible to rotate, size-cap, and otherwise control without drastic interference in your dæmon's operation.

daemontools-family service managers all do logging by having the output of one main service connected, through an ordinary pipe, to the input of another log service. This pipe is set up by the service manager. You don't do it yourself.

The log service is another service. It runs one of the many available tools that simply read from their standard input and write to a strictly size-capped, automatically cycled, on-demand rotateable, set of log files in a log directory.

These programs are multilog,multilog, s6-log, tinylog, cyclog, and svlogd which latter is the one that you'll find that comes in the toolkit with runit.

In fact, you might find that whoever set up /etc/service/MyApp has already set up a log service in /etc/service/MyApp/log . If not, a log service script is dead simple:

#!/bin/sh -e
exec chpst -uMyApp-log svlogd -t ./main

Just create a user account named MyApp-log, mkdir /etc/service/MyApp/log/main, chown MyApp-log /etc/service/MyApp/log/main and you are away. (Note that main can be a symbolic link to somewhere else where you make the directory instead. You don't have to put logs under /etc with runit. I put my log directories under /var/log/sv.)

You do nothing at all to your main service to cycle and size-cap logs. The cycling and size-capping happens independently, in the log service process.

Further reading

Share:
6,602

Related videos on Youtube

Eric Olson
Author by

Eric Olson

Updated on September 18, 2022

Comments

  • Eric Olson
    Eric Olson over 1 year

    I am facing an issue with a script I have kicked off through /etc/service and is using runit.

    My script at /etc/service/myApp/run looks like:

    #!/bin/bash
    cd /src
    forever -l forever.log -o out.log -e err.log -a start bin/www
    

    What Forever does is runs my script as a daemon. But doing this seems to make runit think that my service has ended and runs /etc/service/myApp/run again, and again, and again...

    I have also tried running this not as a daemon and it works fine running in the foreground, but then I still have an issue. I have a clean-shutdown command to send to my server at some point which will eventually shut down the foreground process and I do not want it to restart. But to my dismay, /etc/service/myApp/run gets called immediately to restart my server :(

    I am no sys admin so most of this side of things is new to me. All I want is my script to run on boot and not auto-restart. Thanks for your help.

    EDIT: I updated my question to include the fact that runit is being used here. I see that runit monitors processes to keep services up. My question still remains though.

    • JdeBP
      JdeBP almost 9 years
      /etc/services is not a directory. If you mean /etc/service and you are using runit, then edit your question to correct it and to say so. (There's an easy answer for runit, but it rather presumes that you are using runit.)
    • Eric Olson
      Eric Olson almost 9 years
      Thanks @JdeBP. I found that I am using runit and updated my question accordingly. Thanks for the guidance. I look forward to your "easy answer" :)
  • Eric Olson
    Eric Olson almost 9 years
    Wow! What a great answer @JdeBP. This was like a mini-lesson with multiple answers sprinkled in. I ran and tested with success without using forever and the magical sv down /etc/service/MyApp you suggested. Thank you so much for such detailed and awesome help. The knowledge shared is better than the answer.