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

Hi -- I have a process that runs fine from a unix command line:
foo&
I'd like this to be fired off from a Mason page (modperl2, apache2). This is not on a public site, and  foo& is benign, and foo is smart enough not run multiple copies of itself.

Is

system('/path/to/foo&');
a reasonable way to invoke a backgrounded foo from a Mason page, or is something more complicated needed? If so, why?

Thanks

water


Update:

the setsid solution offered below worked fine for me, once I got over a simple (but for me hard-to-find) bug: foo& worked fine from a command line, but wasn't working from w/in mason/apache/modperl because the system had neglected to set a slew of required environment variables. Once I figured that out, and included an appropriate source

my $rc = system("source /path/to/.profile; setsid /path/to/foo &");
then all worked great.

Many thanks!

Replies are listed 'Best First'.
Re: apache2 and system
by etcshadow (Priest) on Sep 28, 2004 at 01:40 UTC
    What you'll actually want to do is something more like:
    my $pid = fork; die "Error forking: $!" unless defined $pid; if (!$pid) { my $pid = fork; die "Error forking: $!" unless defined $pid; if (!$pid) { exec("/path/to/foo"); } else { CORE::exit; } }

    There are two important things in that:

    • You can't just say system("foo &"); to background foo. The problem is that a shell is invoked to execute "foo &", and, even though foo, itself, gets backgrounded (by that shell process), the shell process is waiting on the backgrounded job, and your perl process's call to system() is, in turn, waiting on the shell process... so you're really not accomplishing what you want (which is that foo can run entirely disconnected from your perl process).
    • I'm forking twice before launching foo. The reason for two forks is so that you can get a process that is entirely disconnected from the perl process. That is, the "foo" process won't appear as a child of the perl process, and won't send $SIG{CHLD}s back to the parent, or various other things that would otherwise be problematic (particularly in mod_perl). This double-fork with the middle-process exiting is a common idiom for completely disconnecting a child process (by making it not a child, but a grandchild, and killing the immediate child), and you can find mention of it in docs if you search for "child of init".

    Anyway, hope that helps.

    ------------ :Wq Not an editor command: Wq
      The shell launched by system doesn't seem to wait for the background process to complete, at least not in my tests. If the OS has an setsid shell command, is there any advantage of using fork and exec over just:
      system('setsid sleep 1000 &');
      It seems to work here.

      Also, the OP may want to think about what to do with open filehandles. It's possible the effects of having a second copy of STDOUT open by the child process will cause strange behavior (like never seeing EOF on a pipe/socket to that filehandle). Redirecting to /dev/null would solve that: system('setsid sleep 1000 </dev/null >/dev/null 2>/dev/null &');

        You're totally right, I spoke before I tested <smacks self>.

        It's easy enough to see if you just do something like:

        perl -e 'system("sleep 10")'
        which returns imediately. I must have been thinking about something else. (Particularly, I think I was thinking of some recent question in which someone wanted the exit status of the backgrounded process... and that's not at all the same issue... oh, well)
        ------------ :Wq Not an editor command: Wq
      many thanks. could that helpful code snippet go onto a mason page inside apache2 w/o ill effect?
Re: apache2 and system
by bsdz (Friar) on Sep 28, 2004 at 07:15 UTC
    Maybe your system has a nohup command. So one could try: -
    ... system('/usr/bin/nohup /path/to/foo'); ...
    This will stop the process hanging up when the shell terminates. On some systems nohup produces a nohup.out file in the current directory or your $HOME environment that you may be able to monitor as a web page.
Re: apache2 and system
by nite_man (Deacon) on Sep 28, 2004 at 07:04 UTC

    I'm not quite sure that I understand why do you want execute foo from web page. But if you need to exec some long running operation from your web page you can do it by following algorithm:

    • Create job queue (in the database, for example)
    • Run foo by cron (every minute, for example)
    • In your web page you just create new task with all needed parameters and store it the queue
    • When foo find out uncompleted task it will process that task and store result code
    I use this approach to send emails, copy result files to other servers (it's difficult to copy file using SSH via HTTP, for example).
    Also, to improve processing of task you can use count of unsuccessful results and exclude from process list tasks which exceeded some limit.

    ---
    Michael Stepanov aka nite_man

    It's only my opinion and it doesn't have pretensions of absoluteness!

Re: apache2 and system
by water (Deacon) on Sep 28, 2004 at 04:07 UTC
    I cannot seem to get either system or the double-fork approach to work. system returns return code = 0 (and returns rc=-1 if I giver it the wrong path), but the process does not start (it logs to as file upon start, so I think it isn't starting. And ideas much appreciated!