Howdy Karjala,

On 22-Apr-06, at 8:47 AM, Karjala wrote:
What would be a good way to launch an external script from a Mason page that would run independently?

From a plain Perl script I would do a fork and have the second process launch the external script and exit, but I guess a fork is out of the question for Mason.

I would do: system("external.pl &") followed by system("disown %1"), but I'm not sure if that would work (and correctly 100% of the time). What if, for example, external.pl hasn't become job %1 yet when the disown command is called?

Do you think this is a good way to launch?


To chime in with another 2¢, here's a sample fork() subroutine that I've been using with great success -- completely forks from the Apache process, and dissociates from the Apache process group (so that it doesn't die if you kill Apache) and relinquishes all open handles (so it doesn't block if you try to re-start Apache and the forked process is still running).

I grabbed most of the theory for this code from the URL below about how to properly fork() under mod_perl, but it was a few years ago and just fair warning -- I'm not 100% positive the way below is still "best practice".

I can vouch that it works fine under Apache/*nix/mod_perl and also under CGI-Perl/Win/IIS.


And here's the subroutine that I use. It returns true to the child, false to the parent. You can use it something like:

use MyPackage qw(ForkMe);

if ( ForkMe() ) {

  # child here

  # some long process
  sleep (300);

  # all done
  # remember: CORE::exit() in the child otherwise might get zombie apache processes
  CORE::exit();

} else {

  # parent process here
  $m->print("Subprocess started.");
}


MyPackage
========

use POSIX ();

# Running under mod_perl?
BEGIN {
    if( exists $ENV{"MOD_PERL"} ) {
        use Apache;
        use Apache::SubProcess;
    }
}

#
# call as: ForkMe()
# actions: forks the current process and created a *completely indepentent* child process
#          (this is really useful for web application processes that need to do something that
#          takes a long time, and you want to fork with independance from the web server
#          process pool)
#
# returns: true to the child
#          false to the parent
#
#          NOTE: specifically, if modifying code to use ForkMe(), don't forget to CORE::exit() after
#                the child code is run, or you will continue back into the parent codebase!!!
#
#          YANOTE: reread the above -- USE CORE::exit() ESPECIALLY when running under mod_perl, otherwise
#                  you'll create zombie Apache child processes that don't clean up properly!
#
#          (MBB) I have updated this routine with information found at:
#          under the Forking section. See there for more info. The NOTEs above still apply, esp.
#          the use of CORE::exit() after child completion.
#
sub ForkMe {

    # Fork and return
    defined ( my $kid = fork() ) or die "Can't fork: $!\n";

    if( $kid ) {

        # Parent process
        # Wait for the kid
        waitpid( $kid, 0 );
        return( 0 );

    } else {

        # To completely disassociate, need to do one more fork.
        defined ( my $grandkid = fork() ) or die "Kid cannot fork: $!\n";

        if( $grandkid ) {

            # Original kid. Time to die.
            CORE::exit();

        } else {

            # Grandkid. A kid of init now hopefully :-)

            # Close bound sockets if running as server process
            if( exists $ENV{"MOD_PERL"} ) {
                my $r = Apache->request();
                $r->cleanup_for_exec();
            }

            # Move to a neutral directory
            chdir( '/' ) or die "Can't chdir to /: $!";

            # Close open filehandles. You must reopen them in your
            # code if you need them.
            #
            # Note we keep STDERR open and inherited to append to
            # Apache's error log, as this is likely the most useful
            # default treatment. Reopen elsewhere for a dedicated
            # error output.
            close( STDIN );
            close( STDOUT );

            # Disassociate from parent by starting new session
            POSIX::setsid() or die "Can't start a new session: $!";

            # Child process
            return( 1 );
        }
    }
}



_______________________________________________________

Michael Burns
Cosbit Technologies
403-701-2672  / [EMAIL PROTECTED]

AIM: cmikeburns
MSN: cmikeburns
_______________________________________________________

Box 2173, Station M    Calgary, Alberta, Canada    T2P 2M4



Reply via email to