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

Hi,
I have a perl script (generate_report.pl) which generates reports based on dynamically created logs. This script runs on a remote win-2000 machine. The script takes paramters for the generation of the report and it takes a lot of time to run, and once it generates the report it mails it automatically.

To make the process easier, Ive scheduled a batch job to be running at frequent intervals in the remote machine, which keeps looking for an entry in a text file, if there is any, it takes the inputs and feeds it to generate_report.pl. One can make the entry in the text file using a cgi script from a machine in the network.

My question is whether I can use a cgi script to execute the perl script generate_report.pl at that time on a click of a button? The script takes some hours, so I always get an error in IE, or it hangs... This is because if I make an entry in the text file, I have to wait until the next scheduled time of the batch job and then another couple of hours to get the report!

There is no way that the report can be generated faster (even if yes, then 2 hours instead of 3 is only possible!). My only problem is an alternative to running it explicitly in the remote machine.
Thanks!

janitored by ybiC: Retitle from "cgi perl", replace <br>'s with balanced <p>'s for legibility

Replies are listed 'Best First'.
Re: Launch background perl script from CGI
by Roger (Parson) on Dec 11, 2003 at 04:34 UTC
    I can see a race condition that might occur when you start to process the file, and then the background process starts to process the file at the same time. So some form of locking/semaphore is required.

    To only allow one process running, you could create a simple semaphore file, like inprogress.txt, under the data directory, and your generate_report.pl script will look for the semaphore file first before processing, with something like below:

    # check for semaphore file my $data_dir = "C:/data"; my $semaphore = "$data_dir/inprocess.txt"; die "another process is in progress" if -f $semaphore; # create the semaphore file open SEMAPHORE, ">$semaphore" or die "Can not create semaphore"; close SEMAPHORE; # do the processing... # delete the semaphore file at the end # you could put this bit in the END block. unlink $semaphore;
    And also your generate_report.pl script should first generate/write the report to a temp file, and then rename/copy it to the cached final report at the end of processing. So while the report generation is still underway, users could still retrieve the most recently generated report.

    You could let the CGI script to spawn the generate_report.pl script as a background process, when the user clicks the 'Kickoff Processing' button, and then display a message like -

    Please be patient while the report is being generated. This process may take more than 2 hours to complete. You can still refer to the most recent report <here> while the new report is being created.
      Hi Roger,
      Thanks for the reply. I was able to implement the locking mechanism before and I've had no problems. It was made sure that the script was generating only one report at a time. This was done using the batch job that was scheduled as I've said before.
      So if the batch has found one request now, and it is still running during the next time frame, it will ignore the request. It will proceed only when its finished.
      My question is to trigger the generate_report.pl script via cgi instead of the batch job. Thing is the cgi will show the progress of generate_report.pl (if its not already running) forever! and it would time out or give some error.
      Thanks again!
        Didn't I say spawn the script in background? ;-)

        In your cgi script, you just need to do this to kick off a background process -
        # check if the 'Generate Report' button is clicked # if so, then set $generate_report to true. if ($generate_report) { # kick off background processing `C:\\Perl\\bin\\perl.exe generate_report.pl &`; # print some feedback text back to user print $cgi->header, $cgi->start_html, "The generate_report.pl script has started in background", $cgi->end_html; }
        Where the back quotes `` tell perl to run the generate_report.pl script, and the '&' at the end puts the script in background. Your CGI script will return control immediately to the browser, leaving the report generation script to run in the background (without interfering with the browser).