On 11/03/11 15:58, Greg Ercolano wrote:
> I'd suggest instead of using MaxTime, to handle this
> specific set of circumstances, you'd probably want to
> instead put some logic in your script to handle the
> more specific behavior you want.
>
> For instance, I could see having your own "Render Max Time:"
> field in the submit form that passes the value to the
> render script, which in turn would take this value,
> fork()s the render off as a child, and then monitors
> the execution time of the render.
>
> This way the script can decide if it should kill the render,
> and if so, implement its own logic to modify the job.
As an actual perl coding example, here's a unix-specific technique
that defines a function called 'RunCommandMaxTime()' that takes
two arguments: the command to run, and the max # seconds.
So calling it is as simple as:
my $cmd = "yourcommand -arg1 -arg2 .."; # COMMAND TO RUN
my $maxsecs = 800; # HOW MANY SECONDS IS 'TOO LONG'..
RunCommandMaxTime($cmd, $maxsecs);
What follows is the definition of that function, which you can customize
to include whatever post-kill logic you want (see '# ADD POST KILL LOGIC HERE').
You could add this function to the .common.pl file, so that any of the
submit scripts could use it if you wanted.
--- snip
use POSIX;
# RUN A COMMAND WITH A MAXIMUM TIME
# Unix only.
# $1 -- command to run
# $2 -- maximum number of seconds command should take before being killed
#
sub RunCommandMaxTime($$)
{
my ($cmd, $maxtime) = @_;
my $starttime = time();
my $pid = fork();
if ( $pid == -1 )
{
# ERROR
print "ERROR: fork() failed?! $!\n";
exit(1);
}
elsif ( $pid == 0 )
{
# CHILD PROCESS
POSIX::setsid();
exec($cmd);
print "ERROR: exec() failed: $!\n";
exit(1);
}
else
{
# PARENT -- WATCH CHILD
my $childpid = $pid;
my $exitstatus = 0;
my $killed = 0;
while ( 1 )
{
# WATCH THE CHILD PROCESS
# See if it finished, and if so, reap.
# If it didn't, see if maxtime expired. If so, kill and reap.
# Otherwise, keep waiting..
#
my $kid = POSIX::waitpid($childpid, WNOHANG); # see if child finished
if ( $kid > 0 ) { $exitstatus = $?; last; } # finished? reap + break loop
# SEE IF MAXTIME EXPIRED
if ( ( time() - $starttime ) > $maxtime )
{
print STDERR "\n--- MAXTIME EXPIRED! Killing child..\n";
kill(-9, $childpid); # -9 means kill *process group*
$killed = 1;
# Add logic here that you want to do if maxtime expired
}
sleep(1);
}
# CHILD FINISHED
if ( $killed ) { print STDERR "--- Render took too long and was killed.\n"; exit(1); }
print STDERR "Child finished in time. EXITCODE=" . ($exitstatus >> 8) . " (status=$exitstatus)\n";
}
}
--- snip
PS. If you're instead using windows, you'd have to replace the fork()/exec() stuff
with the WIN32 equivalent, which in activestate perl is possible with
'use Win32::Process;' and a combo of Win32::Process::Create() to background
the child, and Wait() with some number of seconds, and GetExitCode().
There's actually an example of this in .common.pl
To handle killing the process, I would stay away from any of the win32 stuff,
and simply call 'rush -fail $ENV{RUSH_FRAME}' to cause the script to
commit suicide "cleanly", as the logic for getting that right is tricky
to do from a script.
If I decide on vacationing in the sixth circle of hell, I can follow up with
the WIN32 equivalent code.
|