It's way harder than it should be to have a CGI script do something asynchronously in Apache. The root of the problem is that it's not enough to fork a child, you have to close stdin, stdout, and stderr. Only you can't really close them, you have to reassign them.
import sys, os, time

print "Content-Type: text/plain\n\n",
print "Script started"

if os.fork() == 0:
    # Reassign stdin, stdout, stderr for child
    # so Apache will ignore it
    si = file('/dev/null', 'r')
    so = file('/dev/null', 'a+')
    se = file('/dev/null', 'a+', 0)
    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())
    # Do whatever you want asynchronously
    time.sleep(2)
    os.execv('/bin/sleep', ['sleep', '5'])

print "Process was forked"
This is explained pretty well in Perl and in Python. It's a shame that sys.stdin.close() doesn't work.

I still haven't seen a good explanation for why Apache doesn't send partial output from a CGI: Apache says it doesn't buffer and neither does python -u. Grr. Ah ha, mod_gzip does buffer, unsurprisingly.

Thanks to Marc for research help
techpython
  2004-02-21 21:09 Z