Following on from my
href="http://paddy3118.blogspot.com/2009/03/batch-process-runner-in-bash-shell.html"
target="_blank">Batch process runner script, I got
thinking that a nice capability would be to have a maximum runtime
limit for the jobs.
My first thought was to create an
href="http://unixhelp.ed.ac.uk/CGI/man-cgi?at" target="_blank">at
command set to execute the reuired time after the start of each job,
one for each job, that would kill the job.
Nah.
Discussions with a friend lead to consideration of using
href="http://docs.sun.com/app/docs/doc/816-5165/ulimit-1?l=en&a=view&q=ulimit"
target="_blank">ulimit in the script to limit the
run time, but unfortunately on the Unix box I was testing on, ulimit
could only limit the maximum CPU time, not run time. If the job was
stuck in a non-busy wait then it would not be auto-killed.
I decided to try creating a script to run a time eating processing task
that created a background kill task so the script would be self
killing.
The script
Line 1: The KILLAFTER environment
variable will kill the script after 3 seconds
Line 5: Store the process ID for the
'bash -c' script for killing later
Line 8: This is the slleping background
sub-process that wakes after KILLAFTER seconds and kills the script.
Line 9: But if the normal script commands
finish, store the sub-process PID so it can be cleanly killed itself.
Line 12: Some dummy command that counts up every second.
Line 13: And save its exit status so it can be
restored after removing the background kill process.
Line 16: Terminate the background kill process so
we are not left waiting.
Line 18: Exit with the saved exit status.
Line 19: Prints the exit status of the whole 'bash
-c' script
Lines 20-24 show the output of the first run. Notice how although the
for loop in line 12 is set to count to 5, the count gets killed after
printing 3, i.e. the three seconds of $KILLAFTER.
Lines 27 onwards show a second run where KILLAFTER is set to more time
than is used by the for loop. Notice how the script prints the full
count up to 5, and has a return status of zero.
1 bash-paddy: style="font-weight: bold;">env style="font-weight: bold;" color="#008080">KILLAFTER style="font-weight: bold;">= style="font-weight: bold;" color="#ff00ff">3 style="font-weight: bold;"> bash style="font-weight: bold;" color="#6a5acd">-c style="font-weight: bold;"> '
color="#804040"> 2 # New bash script shell environment
color="#804040"> 3
color="#804040"> 4 # Its PID
color="#804040"> 5 export color="#008080">thisshellpid color="#804040">= color="#a020f0">$$
color="#804040"> 6
color="#804040"> 7 # Sleeping killer will blast this script after given time
color="#804040"> 8 (sleep color="#a020f0">$KILLAFTER color="#804040">; color="#804040">kill color="#ff00ff">-9 $thisshellpid color="#804040">) color="#804040">&
color="#804040"> 9 killerpid= color="#a020f0">$!
color="#804040">10
color="#804040">11 # Any time consuming command
color="#804040">12 for y color="#804040">in color="#ff00ff">1 2 color="#ff00ff">3 4 color="#ff00ff">5; color="#804040">do sleep color="#ff00ff">1; color="#804040">echo color="#ff00ff"> $y color="#804040">; color="#804040">done
color="#804040">13 trueexitstatus= color="#a020f0">$?
color="#804040">14
color="#804040">15 # If time consuming command worked OK then...
color="#804040">16 kill color="#ff00ff">-9 $killerpid
color="#804040">17
color="#804040">18 exit color="#a020f0">$trueexitstatus
color="#804040">19 style="font-weight: bold;">' style="font-weight: bold;" color="#804040">; style="font-weight: bold;"> style="font-weight: bold;" color="#804040">echo style="font-weight: bold;" color="#ff00ff"> Returned status: style="font-weight: bold;" color="#a020f0">$?
color="#804040">20 1
color="#804040">21 2
color="#804040">22 3
color="#804040">23 Killed
color="#804040">24 Returned status: color="#ff00ff">137
color="#804040">25 bash-paddy:
color="#804040">26 bash-paddy:
color="#804040">27 bash-paddy: style="font-weight: bold;">env style="font-weight: bold;" color="#008080">KILLAFTER style="font-weight: bold;">= style="font-weight: bold;" color="#ff00ff">10 style="font-weight: bold;"> bash style="font-weight: bold;" color="#6a5acd">-c style="font-weight: bold;"> '
color="#804040">28 # New bash script shell environment
color="#804040">29
color="#804040">30 # Its PID
color="#804040">31 export color="#008080">thisshellpid color="#804040">= color="#a020f0">$$
color="#804040">32
color="#804040">33 # Sleeping killer will blast this script after given time
color="#804040">34 (sleep color="#a020f0">$KILLAFTER color="#804040">; color="#804040">kill color="#ff00ff">-9 $thisshellpid color="#804040">) color="#804040">&
color="#804040">35 killerpid= color="#a020f0">$!
color="#804040">36
color="#804040">37 # Any time consuming command
color="#804040">38 for y color="#804040">in color="#ff00ff">1 2 color="#ff00ff">3 4 color="#ff00ff">5; color="#804040">do sleep color="#ff00ff">1; color="#804040">echo color="#ff00ff"> $y color="#804040">; color="#804040">done
color="#804040">39 trueexitstatus= color="#a020f0">$?
color="#804040">40
color="#804040">41 # If time consuming command worked OK then...
color="#804040">42 kill color="#ff00ff">-9 $killerpid
color="#804040">43
color="#804040">44 exit color="#a020f0">$trueexitstatus
color="#804040">45 style="font-weight: bold;">' style="font-weight: bold;" color="#804040">; style="font-weight: bold;"> style="font-weight: bold;" color="#804040">echo style="font-weight: bold;" color="#ff00ff"> Returned status: style="font-weight: bold;" color="#a020f0">$?
color="#804040">46 1
color="#804040">47 2
color="#804040">48 3
color="#804040">49 4
color="#804040">50 5
color="#804040">51 Returned status: color="#ff00ff">0
color="#804040">52 bash-paddy:
color="#804040">53