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

I'm obviously doing something silly but I can't seem to start a daemon with Proc::Daemon :(

Here's the code:

use Proc::Daemon; my $daemon = Proc::Daemon->new( ); my $child_pid = $daemon->Init; if ($child_pid) { # We are the parent - we need to exit so Apache shows what # we just printed to the user warn "Child PID is $child_pid\n" if $DEBUG; exit; } my $status = system @cmd; # send an email after completion instead of updating the page

This code is in a CGI script. I want to start a long-running program (as described by @cmd) and then have the parent CGI exit so Apache displays the 'job started' page that the CGI script has already printed.

When the long-running program finishes, the child daemon needs to check the exit status and send an email to advise the user of the result

What's happening is that the CGI script doesn't get its page printed until the long-running program finishes (or Apache times out the CGI if it really is a long-running program!). I presume I'm missing something blindingly obvious, but I can't see what it is and I need to get this working, so thanks for any ideas

Replies are listed 'Best First'.
Re: Proc::Daemon not detaching (KISS)
by tye (Sage) on Mar 20, 2014 at 14:38 UTC

    Daemonizing isn't hard but the source code for Proc::Daemon sure makes it look hard. My searching for daemonize didn't find anything simpler. Maybe there is a bug hidden in that complexity. Just keep it simple?

    use POSIX 'setsid'; $SIG{HUP} = 'IGNORE'; #chdir('/') # Not required in your case; maybe not desired. # or die "Can't cd /: $!\n"; for( 1,0 ) { my $pid = fork(); die "Can't fork: $!\n" if ! defined $pid; exit if $pid; if( $_ && -1 == setsid() ) { die "Can't setsid: $!\n"; } } open STDIN, '<', '/dev/null' or die "STDIN: $!\n"; open STDOUT, '>', '/dev/null' or die "STDOUT: $!\n"; open STDERR, '>&', \*STDOUT or die "STDERR: $!\n";

    At least that will split the difference as to if the problem is a bug in daemonization when you use that module in that way.

    - tye        

      I tried commenting out the Proc::Daemon code and substituting this inline code and it fixed my problem

      So thanks a lot!

Re: Proc::Daemon not detaching
by Corion (Patriarch) on Mar 20, 2014 at 12:06 UTC

    The documentation of Proc::Daemon claims to close STDIN and STDOUT, but the behaviour seems as if the child still keeps STDIN and STDOUT to Apache open. Maybe if you close the handles before launching the child daemon, things work better?

      I tried closing STDOUT, STDIN and STDERR with no apparent difference. A further oddity I've noticed is that when it does actually finish (by running a 'long' program that isn't really all that long), the page returned by Apache from the CGI contains two copies of the message, though only one copy of debug messages in the log.

      My code now looks like this, including the bit of code before the extract I showed

      binmode(STDOUT, ":unix"); # unbuffer STDOUT print $q->header( -status => '200 Pages Updated', -type => 'text/plain', -charset => 'ascii', ); print "\n\nStarting Update of $app_name\n\n" . "Since this will take a while, we will send a mail " . "when it is complete\n"; warn "Forking '@cmd'\n" if $DEBUG; use Proc::Daemon; my $daemon = Proc::Daemon->new( ); close STDIN; close STDOUT; close STDERR; my $child_pid = $daemon->Init; if ($child_pid) { # We are the parent - we need to exit so Apache shows what # we just printed to the user # warn "Child PID is $child_pid\n" if $DEBUG; exit; } my $status = system @cmd; # send an email after completion instead of updating the page

      The 'Starting Update...' text appears twice on the HTML page, but the 'Forking...' message only appears once in the log. A single email message is sent as well.

Re: Proc::Daemon not detaching
by flexvault (Monsignor) on Mar 20, 2014 at 14:31 UTC

    Hi Dave,

    I used to start daemons with Apache 1.x.x, but those days seem over. With Apache 2.x.x, I have not been able to do this. Maybe there is a Apache configuration parameter to allow this, but I have had to change a lot of cgi scripts because of this.

    My solution was to start a long running daemon before or at Apache startup that monitors a file for commands from the cgi scripts. This daemon does not execute the commands, but forks a copy to execute the command. Note: Make sure you put a 'sleep' or 'usleep' in the test loop.

    Apache2 doesn't know the daemon exists, and it works.

    Regards...Ed

    "Well done is better than well said." - Benjamin Franklin

      If the problem is Apache's doing, then you should first get Apache out of your hair before you daemonize. That will prevent Apache from having replaced fork() or POSIX::setsid() or other shenanigans that I wouldn't put past them.

      if( ! @ARGV ) { # CGI code here my $pid = CORE::fork(); die "Can't fork: $!\n" if ! defined $pid; exit # or return, or whatever makes most sense to finish CGI p +art if $pid; CORE::exec( 'perl', $0, 'daemon' ); die "Can't exec perl: $!\n"; } # Rest of code here

      - tye