user3430745
user3430745

Reputation: 33

Run a background process in perl, don't wait for it to finish

EDIT: found a solution here: http://www.webmasterworld.com/forum13/4416.htm

Apparently it's way easier to do on Linux servers than Windows, google came through.

#Print out whatever you're going to print 
print "Stuff in progress. Thanks."

# Close the I/O handles 
close(STDIN); 
close(STDOUT); 
close(STDERR); 
# run your other code here

I don't work in perl at all so the easiest solution is best for me. I'm just trying to figure out how to modify this program to make it do what I want.

Basically what this program is the broker for a UI. What it does is take a program name, print commands to a SAS program file including which SAS program to run to create output, then runs the SAS program, which then outputs the $pname.out file at the end, which is what is finally printed to the UI screen.

The latest SAS program created can take a long time, so I plan to to run the SAS program in the background as the child and have the SAS send an email when it's done.

In the foreground i.e. parent, I want to have the perl program return a screen with some basic info.

So my question basically is, how do I tell perl to run the child process in the background and not wait for it to be done?

I tried "&" on the end of the system ("$SASROOT $saschild") command, but it just prevented the program from running at all. If I use the command without "&", the program doesn't return anything to the browser screen until the child is done running.

Any help would be appreciated!

#!perl


use CGI ;



# YOUR MODIFICATIONS START HERE 

$TEMPFILES = "c:\\temp"; # This is the directory SAS will write its temporary files
$PROGROOT = "c:\\Inetpub\\wwwroot\\Effectiveness"; # This is the directory that contains the SAS programs to run
$DATAROOT = "c:\\Inetpub\\wwwroot\\Effectiveness" ; # This is the directory that contains the SAS data sets to be analysed

$SASROOT = "D:\\SAS\\SASFoundation\\9.2\\sas.exe"; # This is the full path name of the SAS System
$CGIBIN = "\\" ; # This is the alias of cgi-bin directory

$HTTPURL ="http://10.240.7.172" ;

$WEBROOT = "c:\\Inetpub\\wwwroot\\Effectiveness" ; # This is the root directory of webserver
$SASCFG = "d:\\SAS\\SASFoundation\\9.2\\SASV9.CFG" ; # This is the path to SAS config file

# YOUR MODIFICATIONS END HERE 

&get_request;

$PROGFILE = $rqpairs{'_program'};

if (!($PROGFILE =~ /^(\w[\w\.\-]+)$/))
{
    &error("The hidden field <CODE>_program</CODE> (= \"$PROGFILE\") is invalid or missing.");
}

$SASPROG="$PROGROOT\\$PROGFILE.sas";

if (!-f $SASPROG)
{
    &error("The program file \"$SASPROG\" does not exist.");
}


$pname = "p$$"; 
$cname = "c$$" ;
$repname = "r$$" ;

$random = int(rand("$$")); 
$pname = "$pname$random" ;
$cname = "$cname$random" ;
$repname = "$repname$random" ;


open(OUTCON, "+>>$TEMPFILES\\$cname.sas") ;
   print OUTCON "-set outfl \"$TEMPFILES\\$pname.out\" \n" ;
#print OUTCON "%include \"$TEMPFILES\\config.tpl\" \n";
   print OUTCON "%include \"$SASCFG\" \n";
close(OUTCON) ;


open(OUTFI,"+>>$TEMPFILES\\$pname.sas");


print OUTFI "options set=cgibin \"$CGIBIN/broker.pl\" ; \n" ;
print OUTFI "options set=location \"$DATAROOT\" ; \n" ;
print OUTFI "options set=webroot \"$WEBROOT\" ; \n" ;
print OUTFI "options set=outfl \"$TEMPFILES\\$pname.out\" ; \n" ;

print OUTFI "options set=outrep \"$WEBROOT\\$repname.xls\" ; \n" ;
print OUTFI "options set=repline \"$HTTPURL\\broker.pl?_program=_result\" ; \n" ;
print OUTFI "options set=excel_file=\"$repname.xls\" ; \n" ;

print OUTFI "options mprint ; \n" ;



while ( ($name,$value) = each %rqpairs )
{

 $value =~ s/([%()])/%$1/g ;


# $value =~ tr/ /\n/s ;
# $value =~ tr/,/,\n/s ;

# $in_string =~ tr/\+/ /s; # translate and squeeze multiple spaces


     if ($name ne "var")
   {
       print OUTFI "%let $name = %nrstr($value);\n";
   } 
}



print OUTFI "%include \"$SASPROG\";\n";
close(OUTFI) ;

$sasoptions = " -nodms -sysin $TEMPFILES\\$pname.sas -log $TEMPFILES\\$pname.log -work $TEMPFILES -sasuser $TEMPFILES" ;




#THIS IS THE FORKING OF THE PROCESS - only fork for rfcost application
my $pid = fork();
if (defined $pid && $pid == 0){

    #child
    close STDIN; #close connections to webpage
    close STDOUT; #close connections to webpage
    $saschild = " -nodms -sysin $TEMPFILES\\TestOutput.sas -log $TEMPFILES\\TestOutput.log -work $TEMPFILES -sasuser $TEMPFILES" ;


    system ("$SASROOT $saschild");
    exit(0);

}

#   sleep(120);
system ("$SASROOT $sasoptions");



#system ("$SASROOT -rsasuser -noterminal -sysparm -sysin $TEMPFILES\\$pname.sas -log $TEMPFILES\\$pname.log -config $TEMPFILES\\$cname.sas");


    print "HTTP/1.0 200 OK\n";
    print "Content-type: text/html\n\n";

    &html_trailer;

#print "$sasoptions" ;

   open (FILE, "$TEMPFILES\\$pname.out");
    while (<FILE>){ print; }
    close (FILE);

    &html_trailer;

#unlink("$TEMPFILES/$pname.sas");
#unlink("$TEMPFILES/$pname.log");
#unlink("$TEMPFILES/$pname.lst");
#unlink("$TEMPFILES/$pname.out");
#unlink("$TEMPFILES/$cname.sas");

sub get_request 
{

    if ($ENV{'REQUEST_METHOD'} eq "POST") {
        read(STDIN, $request, $ENV{'CONTENT_LENGTH'});
    } elsif ($ENV{'REQUEST_METHOD'} eq "GET" ) {
        $request = $ENV{'QUERY_STRING'};
    }

    %rqpairs = ();
    @rqarray = &url_decode(split(/[&=]/, $request));

    while ( $key = shift(@rqarray) )
       {
       $value = shift(@rqarray);

       if ( $rqpairs{$key} ne "" )
          {
          $rqpairs{$key} .= "," . $value;
          }
       else
          {
          $rqpairs{$key} = $value;
          }
       }
}

sub url_decode 
{


    foreach (@_) 
    {
        tr/+/ /;
        s/%(..)/pack("c",hex($1))/ge;
    }
    @_;
}

sub html_header 
{

    local($title) = @_;

    print "HTTP/1.0 200 OK\n";
    print "Content-type: text/html\n\n";
    print "<html><head>\n";
    print "<title>$title</title>\n";
    print "</head>\n<body>\n";
}

sub html_trailer 
{


    local($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst)
        = gmtime;

    local($mname) = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
                     "Aug", "Sep", "Oct", "Nov", "Dec")[$mon];
    local($dname) = ("Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
                    "Sat")[$wday];
#    print "<br><p>Date: $hour:$min:$sec on $dname $mday $mname $year</p> \n" ;
    print "</body></html>\n";
}


sub error 
{

    local($msg) = @_;
    &html_header("SAS CGI Process Error");
    print "<H1>SAS CGI Process Error</H1>\n$msg\n";
    &html_trailer;
    exit 1;
}

Upvotes: 1

Views: 4139

Answers (2)

Mekk
Mekk

Reputation: 1459

There are various CPAN modules which may make task easier, for example http://search.cpan.org/~bzajac/Proc-Background-1.10/lib/Proc/Background.pm

Having said that, I'd consider introducing some job queue, so your process puts task into the queue and separate process picks it up to handle, more manageable...

Upvotes: 1

Kescha Skywalker
Kescha Skywalker

Reputation: 489

Use exec (as quicoju suggested) to execute a command in background

See here for more details: http://perldoc.perl.org/functions/exec.html

exec PROGRAM LIST

The exec function executes a system command and never returns; use system instead of exec if you want it to return. It fails and returns false only if the command does not exist and it is executed directly instead of via your system's command shell (see below).

A very good answer you will find in this thread: What's the difference between Perl's backticks, system, and exec?

Upvotes: 1

Related Questions