asiufy has asked for the wisdom of the Perl Monks concerning the following question:

Monks,

I would like to have my scripts/daemons start up with : daemon.pl start, and quit (gracefully) with daemon.pl stop. Of course, I would like it also to respond to command line kill attempts...

The problem is that not only I am not entirely familiar with Unix signal handling (working on it...), but I also don't know what steps I should take in the Perl code itself to make sure that the daemon quits after finishing whatever task it was doing at the time the 'quit' signal came, and log everything...

The Camel book (v3) preaches the use of $SIG{} in conjunction with a sub, but I fear that by doing this way, the program will quit as soon as it receives the signal, which is not exactly what I want...

Thanks!

Replies are listed 'Best First'.
Re: Gracefully exiting daemons
by Zaxo (Archbishop) on Jun 25, 2001 at 01:42 UTC

    Your signal approach is sound. See 'man 7 signal' for a summary of system signals available to you, and the conventions associated with them.

    A full-fledged daemon has no controlling tty, but it's not clear you're taking it that far. In any case, a DESTROY() method may be what you need for cleaning up before the daemon dies. Documentation is in the usual places (perldoc and Camel). It's brief but ought to be enough.

    After Compline,
    Zaxo

Re: Gracefully exiting daemons
by Brovnik (Hermit) on Jun 25, 2001 at 03:33 UTC
    I use the following in a backup script.
    #... $SIG{'INT'} = 'cleanup'; # we want to rewind tape & write to log $SIG{'HUP'} = 'cleanup'; # we want to rewind tape & write to log # later... sub cleanup { # Normal is set to true if the script has got through the # rest. &report("\nAbnormal exit, cleaning up") unless $normal; if ($normal) { &eject(); } else { &rewind(); &eject() if $opt{e}; } # Report and other stuff here deleted. }
    /etc/init.d (on many unixes) will have examples of start/stop scripts. Stopping is often done by signalling using a stored Process ID, so the $SIG{INT} handler handles both unexpected kills and 'normal' kills e.g. from a shutdon command.
    --
    Brovnik
      I could have a global variable being updated throughout the script, with the current state of execution, and in case the signal is trapped, I can then act/log based upon it...

      Almost there, but not entirely what I wanted... Isn't there a way to actually delay the execution of the sub as the signal is received? That would allow the script to finish whatever it was doing at the time (if it was doing anything), and only then die gracefully...
        You can of course catch the signal and do nothing, or (as here) just set a variable for you to look at later.
        $SIG{HUP} = \&catch; my $caught = 0; my $count = 0; print "I am $$, HUP me\n"; for (0..10) { sleep (5); # pretending to do stuff print "$_\n"; } die "I was HUPed $caught times" if $caught; ### Subroutines below sub catch { $caught++; }
        You should of course think carefully about ignoring signals, expecially INT and TERM, since if you get these, someone/something is trying to tell you something.

        But, delaying handling e.g. HUP or USR1 until it is a better time to handle is OK.

        Make sure you document the signal handling well, specially if it is not expected behaviour. E.g. HUP is often used to mean "Please reread your config file".
        --
        Brovnik