How to kill a child script if it takes more than 10 minutes?

Hi all,
I have a query on killing a child process, if it takes more than 10 minutes

myparent.sh has the following

#!/bin/sh

echo "My Parent Script"
home/guru/initiateServer.sh

The initiateServer is a child process and this might take 20 or more minutes to return. I want to kill this process, if it is taking more than 10 minutes.

Please advice on what to do? Thanks all in advance

-Guru

Hi guruincredible,

Your title had the answer, make it a child process and have the main process time the return of the child process.

#!/bin/sh

echo "My Parent Script"
home/guru/initiateServer.sh &
pid=$!
sleep 600
if [ kill -0 $pid ] {
 echo "killing initiateServer as it took too long to complete"
 kill $pid # you could optionally add a -9 in there if the server has a sigterm handler 
}

Dear Skrynesaver,
thanks for the reply. if the child process returns before 10 minutes, say in 3 minutes, 7 minutes will be wasted.

Any way to move on if the child process is not alive, or if took more than 10 minutes, kill and move on?

Please advice.

Good point, also had a cup of coffee and wrote if loop in shell syntax and caught kill -0 return correctly.

New improved scriipt, now with max wasted time of 10 seconds...

#!/bin/sh

echo "My Parent Script"
home/guru/initiateServer.sh &
pid=$!
for i in {0..60} ; do
   kill -0 $pid
   if [ $? -eq 1 ]  ; then
      exit
   fi
   sleep 10
done
kill $pid

Alternatively if this is a subroutine in a larger script use return rather than exit.

How about shedule kill command using at ?

 
#!/bin/sh
echo "My Parent Script"
home/guru/initiateServer.sh &
pid=$!
at now + 10 minutes <<_EOF_
kill $pid 2>/dev/null
_EOF_

Dear pravin27,

You risk either killing an innocent process that happens to have been created later on with the same process id (especially if you are running as the super-user) but you will probably be generating mail. I would go with Skrynesaver's suggestion. Far safer. It might be worth investing a little time in listing the process details at the start and at the end to ensure you are definitely killing the same process.

Robin
Liverpool/Blackburn
UK

I have solved this a year ago:

home/guru/initiateServer.sh &
task=$!
( sleep 600 && kill $task ) </dev/null >/dev/null 2>&1 &
watchdog=$!
wait $task
sleep 1
kill $watchdog >/dev/null 2>&1

This gives a 99% safety that no innocent process is killed.
The 100% method is with perl:

perl -e "alarm 600; exec @ARGV" home/guru/initiateServer.sh

Hi.

See also:

NAME
       timeout - run command with bounded time

SYNOPSIS
       timeout [-signal] time command ...

DESCRIPTION
       timeout  executes  a  command  and  imposes an elapsed time limit.  The
       command is run in a separate POSIX process  group  so  that  the  right
       thing happens with commands that spawn child processes.

and

NAME
     timelimit - effectively limit the absolute execution time of a process

SYNOPSIS
     timelimit [-q] [-S killsig] [-s warnsig] [-T killtime] [-t warntime]
               command [arguments ...]

DESCRIPTION
     The timelimit utility executes a given command with the supplied
     arguments and terminates the spawned process after a given time with a
     given signal.  If the process exits before the time limit has elapsed,
     timelimit will silently exit, too.

Both were in the Debian repository, there may be others as well.

The versions I have are:

timeout - ( /usr/bin/timeout, 2008-04-29 )
timelimit - ( /usr/bin/timelimit, 2008-07-18 )

The latter can also be found at timelimit � limit a process's absolute execution time

Best wishes ... cheers, drl

The following is POSIX-compatible and never signals an "innocent process":

set -m
sh -c '(/path/to/task; kill 0) & (sleep 600; kill 0) &' &

A more readable alternative:

set -m
sh <<'EOF' &
    (/path/to/task; kill 0) &
    (sleep 600; kill 0) &
EOF

If it should wait:

set -m
sh <<'EOF' &
    (/path/to/task; kill 0) &
    p=$!
    (sleep 600; kill 0) &
    wait
EOF
wait

set -m ensures that the non-interactive background shell (and all of its children) which does all the work is placed in its own, dedicated process group, regardless of whether the main script is invoked from an interactive shell or not. From within that process group, any member can signal all other members without affecting outsiders. Even if a pid is reused, it will not be signaled because it will no longer be a member of the process group.

Naturally, stdout and stderr should likely be redirected.

Regards,
Alister

Thanks, it's even in man sh : kill 0 kills the "process group". (I thought it only kills itself.)
And works with a traditional Unix shell, too.

---------- Post updated at 07:26 AM ---------- Previous update was at 06:15 AM ----------

I just checked my old script - it uses this in a loop, so kill 0 cannot be used.

I've made it work on AIX (4.3.3, 5.1 & 6.1) , HP-UX (11.11i) and RHEL (6.3)

I saved and ran this demo:-

set -m
date
sh <<'EOF' &
    (ping -c 50 localhost ; kill 0) &
    p=$!
    (sleep 6; kill 0) &
    wait
EOF
wait
date

I got the output:-

$ script_timeout_demo
Thu  6 Jun 13:59:05 2013
PING loopback (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=0 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=255 time=0 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=255 time=0 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=255 time=0 ms
64 bytes from 127.0.0.1: icmp_seq=4 ttl=255 time=0 ms
64 bytes from 127.0.0.1: icmp_seq=5 ttl=255 time=0 ms
64 bytes from 127.0.0.1: icmp_seq=6 ttl=255 time=0 ms
Terminated
Thu  6 Jun 13:59:11 2013
$

I had to change the ping command on HP-UX, because that syntax is ping localhost -n 50

Some give variations on the Terminated message, but that can be handled/ignored/re-directed.

So, alister - absolutely fantastic. You should see some of the rubbish I've coded in the past to try to do the same sort of thing. I regret that I can only thank a post once.

Robin

Could you please post your code, or a simplified yet fully-functional structural equivalent?

Your "99%" solution is probably more like a "99.9999%" solution. It's extremely unlikely that you need anything better. However, I'm interested to see if yours is a situation in which I cannot make my approach work.

So long as the only things in the process group are the monitored and monitoring processes, I don't see why kill 0 cannot be used.

Regards,
Alister

---------- Post updated at 04:53 PM ---------- Previous update was at 04:44 PM ----------

Regarding rubbish code, we've all been there. I have actually never used this code; it is something I come up with yesterday while pondering this thread and the possibility of a portable solution without a pid race. For that reason I appreciate your multi-platform testing. Thank you very much.

Regards,
Alister