27

I have a Perl script that I want to daemonize. Basically this perl script will read a directory every 30 seconds, read the files that it finds and then process the data. To keep it simple here consider the following Perl script (called synpipe_server, there is a symbolic link of this script in /usr/sbin/) :

#!/usr/bin/perl
use strict;
use warnings;

my $continue = 1;
$SIG{'TERM'}  = sub { $continue = 0; print "Caught TERM signal\n"; };
$SIG{'INT'} = sub { $continue = 0; print "Caught INT signal\n"; };

my $i = 0;
while ($continue) {
     #do stuff
     print "Hello, I am running " . ++$i . "\n";
     sleep 3;
}

So this script basically prints something every 3 seconds.

Then, as I want to daemonize this script, I've also put this bash script (also called synpipe_server) in /etc/init.d/ :

#!/bin/bash
# synpipe_server : This starts and stops synpipe_server
#
# chkconfig: 12345 12 88
# description: Monitors all production pipelines
# processname: synpipe_server
# pidfile: /var/run/synpipe_server.pid
# Source function library.
. /etc/rc.d/init.d/functions

pname="synpipe_server"
exe="/usr/sbin/synpipe_server"
pidfile="/var/run/${pname}.pid"
lockfile="/var/lock/subsys/${pname}"

[ -x $exe ] || exit 0

RETVAL=0

start() {
    echo -n "Starting $pname : "
    daemon ${exe}
    RETVAL=$?
    PID=$!
    echo
    [ $RETVAL -eq 0 ] && touch ${lockfile}
    echo $PID > ${pidfile}
}

stop() {
    echo -n "Shutting down $pname : "
    killproc ${exe}
    RETVAL=$?
    echo
    if [ $RETVAL -eq 0 ]; then
        rm -f ${lockfile}
        rm -f ${pidfile}
    fi
}

restart() {
    echo -n "Restarting $pname : "
    stop
    sleep 2
    start
}

case "$1" in
    start)
        start
    ;;
    stop)
        stop
    ;;
    status)
        status ${pname}
    ;;
    restart)
        restart
    ;;
    *)
        echo "Usage: $0 {start|stop|status|restart}"
    ;; esac

exit 0

So, (if I have well understood the doc for daemon) the Perl script should run in the background and the output should be redirected to /dev/null if I execute :

service synpipe_server start

But here is what I get instead :

[root@master init.d]# service synpipe_server start
Starting synpipe_server : Hello, I am running 1
Hello, I am running 2
Hello, I am running 3
Hello, I am running 4
Caught INT signal
                                                           [  OK  ]
[root@master init.d]# 

So it starts the Perl script but runs it without detaching it from the current terminal session, and I can see the output printed in my console ... which is not really what I was expecting. Moreover, the PID file is empty (or with a line feed only, no pid returned by daemon).

Does anyone have any idea of what I am doing wrong ?

EDIT : maybe I should say that I am on a Red Hat machine.

Scientific Linux SL release 5.4 (Boron)

Thanks, Tony

tony
  • 618
  • 1
  • 6
  • 12
  • 3
    Instead of writing a daemon to poll for changes, you could use inotify http://en.wikipedia.org/wiki/Inotify to inform you when a change has happened. It's easier to code for, more efficient, and can see updates faster. There's a number of CPAN modules to talk with it. http://search.cpan.org/search?query=inotify&mode=all – Schwern Nov 14 '11 at 19:29
  • Thanks, this is useful info, I will definitely have a look at Inotify. – tony Nov 14 '11 at 19:50
  • @Schwern : that does not change the fact that I have to run a daemon in the background waiting for inotify notifications, no ?? – tony Nov 15 '11 at 08:10
  • That's true. I can't help you with the details of the daemon command on Redhat. It differs from system to system. – Schwern Nov 16 '11 at 02:28

4 Answers4

17

I finally re-wrote the start function in the bash init script, and I am not using daemon anymore.

start() {
    echo -n "Starting $pname : "
    #daemon ${exe} # Not working ...
    if [ -s ${pidfile} ]; then
       RETVAL=1
       echo -n "Already running !" && warning
       echo
    else
       nohup ${exe} >/dev/null 2>&1 &
       RETVAL=$?
       PID=$!
       [ $RETVAL -eq 0 ] && touch ${lockfile} && success || failure
       echo
       echo $PID > ${pidfile}
    fi
}

I check that the pid file is not existing already (if so, just write a warning). If not, I use

 nohup ${exe} >/dev/null 2>&1 &

to start the script.

I don't know if it is safe this way (?) but it works.

tony
  • 618
  • 1
  • 6
  • 12
  • 2
    I used something similar, but used `daemon` alongside nohup to provide output shown when the script has been started. It's more of a visual cue that anything else, since the [OK] message will always return as OK as long as nohup has run: `daemon "nohup ${exe} >/dev/null 2>&1 &"` as an example. – Rohaq Feb 16 '12 at 14:40
  • tony, wouldn't this daemon die when your shell terminates? Or does nohup prevent that? – Mark Aug 24 '12 at 17:02
  • Yes, when the shell terminates, the process created by nohup remains alive. – tony Mar 04 '13 at 14:28
  • I tried the daemon/nohup method but I can't get at the PID that way. Any ideas? – Joe D'Andrea Nov 13 '13 at 21:02
  • @Joe : The shell variable '$!' is the pid of the last process launched in background. Would it be enough for your purposes ? – tony Jan 22 '14 at 08:20
  • @tony: I would think '$!' is enough, but it doesn't come back with anything for some reason. I'm probably doing something wrong. :\ – Joe D'Andrea Jan 22 '14 at 21:24
  • Just in case anyone is interested if you don't really care about echoing a warning if the script is already running you can piggyback the "daemon" function out of the /etc/rc.d/init.d/functions file as it already performs a check to see if the script is already running. As such you can use `daemon "nohup $exe 0<&- &>/dev/null &"`. – crashmaxed Apr 02 '14 at 21:14
3

The proper way to daemonize a process is have it detach from the terminal by itself. This is how most larger software suites do it, for instance, apache.

The rationale behind daemon not doing what you would expect from its name, and how to make a unix process detach into the background, can be found here in section 1.7 How do I get my program to act like a daemon?

Simply invoking a program in the background isn't really adequate for these long-running programs; that does not correctly detach the process from the terminal session that started it. Also, the conventional way of starting daemons is simply to issue the command manually or from an rc script; the daemon is expected to put itself into the background.

For further reading on this topic: What's the difference between nohup and a daemon?

Community
  • 1
  • 1
MarkM
  • 798
  • 6
  • 17
0

As said here, it seems that the process needs to be sent to the background using &. Daemon don’t do it for you.

Community
  • 1
  • 1
Thibault Deheurles
  • 1,211
  • 13
  • 21
0

According to man daemon correct syntax is

daemon [options] -- [command] [command args]

Your init script startup should run something like:

daemon --pidfile ${pidfile} -- ${exe}
yko
  • 2,710
  • 13
  • 15
  • 3
    Thanks yko, but it's not this because my 'daemon' usage says : `daemon [+/-nicelevel] {program}` . Perhaps we do not have the same version. – tony Nov 14 '11 at 17:45
  • @tony I ended up installing [daemon from libslack](http://libslack.org/daemon/#download) – Nanda Kishore Nov 26 '15 at 07:26
  • 1
    The `deamon` @tony is referring to is the one declared by `/etc/rc.d/init.d/functions` – Dacav Jul 21 '16 at 10:32