I am trying to start an asynchronous process from a web application. The idea is that I fork(), then redirect to another page whilst the child process gets on with a lengthy job in the background (simulated by my sleep(20).)

Despite having tried a variety of ways of flushing STDOUT, the parent process always waits for the child to finish. Can anyone see what I'm doing wrong?

The $SIG{CHLD}='IGNORE' was supposed to stop zombie processes, but didn't - I always end up with a [asynctest.pl] <defunct> in my ps output. But zombies are the least of my worries when STDOUT doesn't want to flush.

SOLVED - thanks to ruzam and ikegami for the solution. The child process has to be detached using setsid(). I used Net::Server::Daemonize to simplify this. See Code Listing 2 for the relevant parts, including how I got the required UID and GID for daemonize() and cleaned up the PID file. (The Apache user is different on my development box and the test server - and possibly different again on the production server. This is why the UID/GID has to be considered an unknown.)

It should be noted that the "it's not possible" attitude in Perl FAQ 8 isn't exactly correct and that the system("foo.pl &") recipe produces exactly the same hang that was the problem in the first place.

Code Listing

#!/usr/bin/perl # This is asynctest.pl # Running under Apache 2.2/Linux. use strict; use warnings; use CGI; use IO::Handle; # Tried this: # STDOUT->autoflush(1); my $cgi=new CGI; unless ($cgi->param('a') eq 'foo') { my $pid=$cgi->param('pid'); print<<EOT; Content-type: text/html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head><title>foo</title></head> <body> <p>$pid</p> <form method="post" action="asynctest.pl"> <div><input type="hidden" name="a" value="foo" /></div> <div><input type="submit" value="press me" /></div> </form> </body></html> EOT exit; } else { # Tried this: $SIG{CHLD}='IGNORE'; if (my $pid=fork()) { # Redirect back to home screen, passing # the PID so we can keep an eye on it. print "Status: 302 Moved Temporarily\n"; print "Location: asynctest.pl?c=$pid\n\n"; # Tried this: # # my $old_fh=select(STDOUT); # $|=1; # select($old_fh); # And tried this: # # STDOUT->flush(); # And this: # # close STDOUT; # ...in varying combinations. # But this process always waits # for the sleep() in the other # process before sending the # redirect. exit; } else { close STDOUT; sleep(20); exit; } }

Code Listing 2

(use Net::Server::Daemonize is assumed.)

#snipped if (my $pid=fork()) { $|=; # Set auto-flush. print "Status: 302 Moved Temporarily\n"; print "Location: asynctest.pl?c=$pid\n\n"; close STDOUT; exit; } else { # We don't really need the PID file, but # daemonize() complains if you don't provide it, # despite the manpage saying it's optional. my $pidfile="/var/tmp/async$$.pid"; my @current_user=getpwuid($<); daemonize($current_user[2],$current_user[3],$pidfile); sleep(20); unlink($pidfile); # otherwise it doesn't go away exit; }

In reply to Problems with flushing after fork() by smiffy

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.