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

Hello,

I have a CGI program that takes a long time to save information after a user submits the form. The reason is not that there's a lot of information gathered from the form, but that the program needs to generate this information based on just a few parameters from the user. (It is really a caching feature to pre-generate rarely updated pages and load them from disk instead of constructing the same pages on the fly each time).

What I want to do is to fork a separate process that would deal with saving this information, so that the CGI program can just return the web page and exit. I've tried the code below, but the CGI script still waits for the child to finish saving.

my $pid; if( $pid = fork ){ # parent here # output web page and finish } elsif( defined($pid) ) { # child here # save info and exit exit(0); } else { # fork error }

The Camel Book says that sometimes you have to close open filehandles in the child process before the web server returns the page. I tried closing STDIN, STDOUT and STDERR, but that didn't work.

Perl Cookbook said that I might have to try Win32::Process instead, but I'm not sure if that suits my needs, because I don't need to start a separate standalone process, but just finish saving the information that is shared by both the parent and the child processes.

My system is Windows 2000 running IIS 5. ActivePerl version 5.6.1

Has anyone had any luck with forking on Windows systems? Any sample code or hints or pointers to resources would be highly appreciated!

Thanks!
Alex

Replies are listed 'Best First'.
Re: Forking in a CGI program on Windows systems
by Tanalis (Curate) on Nov 08, 2002 at 16:18 UTC
    From my C days, I understand fork to be a *nix-only command - in fact the Camel (2nd edition) says "The fork function is unlikely to be implemented on any OS not resembling UNIX."

    Win32::Job might do what you need - it'll let you "spawn" a process on Windows, and it's docs contain a couple of good examples.

    Hope that helps ..
    --Foxcub

      Well, you're right of course. But when I used the term "forking", I refered to the general idea, not a particular implementation on a particular system.

      Since you quoted the Camel Book (3rd edition), it then says "...The fork function is unlikely to be implemented efficiently, or perhaps at all, on systems that don't resemble Unix. For example, Perl 5.6 emulates a proper form even on Microsoft systems... ". And, in fact, fork does work on my Windows. I tested it, it works. My question was related to using fork from a CGI program. My problem seems to be that the web server does not output the web page until all shared filehandles are closed or something alone these lines - if I knew exactly what's going and how to fix it I wouldn't be asking that question.

      Win32::Job is *almost* the same (in its functionality) as Win32::Process. As I have mentioned in my post, I would like the spawned process to have access to the shared information, so that it can just simply save it to file. If I used Win32::Process or Win32::Job, it seems to me that I would have to use a pipe or at least command line arguments to transfer the parameters from the CGI program to the spawned process.

Re: Forking in a CGI program on Windows systems
by Mr. Muskrat (Canon) on Nov 08, 2002 at 16:20 UTC

    What I want to do is to fork a separate process that would deal with saving this information, so that the CGI program can just return the web page and exit.

    So then you really don't need to fork do you? Why not have the CGI script output the HTML to show it's done and then run a seperate Perl script that will save the information?

      I'd be glad to do what you suggested - I just don't know how. Maybe I'm misunderstanding something about web servers, but I'm really really not sure how to run something from a CGI program after it has finished.

      Perhaps you could provide a couple of lines of sample code? (Only if it's not too much to ask for, of course.)

        Something like this should work:

        @args = ("command", "arg1", "arg2"); system(@args) == 0 or die "system @args failed: $?";

        Update: Or maybe this is better since exec() doesn't return to the current script:

        @args = ("command", "arg1", "arg2"); exec { $args[0] } @args or print STDERR "couldn't exec $args[0]: $!";

Re: Forking in a CGI program on Windows systems
by relax99 (Monk) on Nov 08, 2002 at 20:10 UTC

    Okay. I think I solved the problem. Turns out fork works fine on at least Windows 2000 systems. I get the web server to output the web page as soon as I close STDIN, STDOUT, and STDERR in the parent process and the child process.

    If anyone needs to see the actual code please let me know. Thanks to everyone for help!

      Hey relax99,
      I was wondering if you would post the code. Here is the code that I'm trying and I'm not able to have my page redirect right away. It still waits until the other process is finished to redirect.
      Thanks for your help!
      if (my $pid = fork)
      {
      	print redirect("buildlist.php");
      }
      elsif (defined $pid)
      {
      close(STDIN);
      close(STDOUT);
      close(STDERR);
      #open STDIN, "</dev/null";
      #open STDOUT, ">/dev/null";
      
      sleep (10);
      open (FILE, "> test.txt");
      print FILE "TESTING CAPABILITY";
      close FILE;
      exit;
      }