| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- #!/bin/sh
- # Usage: job_killer.sh [-c]? [grace_period_seconds] [process_pattern] [sidecar]?
- #
- # This script waits for a termination signal and gracefully terminates another process before exiting.
- #
- # Attempts to gracefully kill a process by sending SIGTERM to the first process that matches
- # the pattern. If "-c" is set, it will also signal all child processes of the main process.
- # All processes are forcibly killed if they have not exited after the grace period.
- #
- # Example: if process that should be killed has start command "./run_job.sh", and grace
- # period should be 30s, would run "./job_killer.sh 30 ./run_job.sh".
- kill_child_procs=false
- while getopts ":c" opt; do
- case $opt in
- c)
- kill_child_procs=true
- esac
- done
- if $kill_child_procs
- then
- grace_period_seconds=$2
- target=$3
- sidecar=$4
- else
- grace_period_seconds=$1
- target=$2
- sidecar=$3
- fi
- global_timeout=$TIMEOUT
- if [ -z "$global_timeout" ]; then
- global_timeout=3600
- fi
- echo "set global timeout value of $global_timeout"
- pattern="$(printf '[%s]%s' $(echo $target | cut -c 1) $(echo $target | cut -c 2-))"
- graceful_shutdown() {
- echo "starting graceful shutdown..."
- local timeout=$1
- echo "searching for process pattern: $pattern"
- local target_pid=$(pgrep -f $pattern -l | grep -v 'job_killer.sh' | grep -v 'wait_for_job.sh' | grep -v 'grep' | awk '{ printf "%d ", $1 }' | sort)
- local list="$target_pid"
- if [ -n "$target_pid" ]; then
- # request graceful shutdown from target_pid
- kill -0 ${target_pid} 2>/dev/null && kill -TERM ${target_pid}
- if $kill_child_procs
- then
- for c in $(ps -o pid= --ppid $target_pid); do
- # request graceful shutdown of all children, and append to process list
- kill -0 $c 2>/dev/null && kill -TERM $c && list="$list $c" || true
- done
- fi
- # schedule hard kill after timeout
- (sleep ${timeout}; kill -9 -${target_pid} 2>/dev/null || true) &
- local killer=${!}
- # wait for processes to finish
- for c in $list; do
- echo "waiting for process $c"
- tail --pid=$c -f /dev/null
- done
- wait ${list} 2>/dev/null || true
- # children exited gracefully - cancel timer
- sleep 0.1 && kill -9 ${killer} 2>/dev/null && target_pid="" || true
- fi
- # run the sidecar killer, this will terminate any additional sidecars if necessary
- if [ -n "$sidecar" ]; then
- echo "killing sidecar command: $sidecar"
- ./sidecar_killer.sh $sidecar
- fi
- echo "Exit Gracefully (0)" && exit 0
- }
- trap 'graceful_shutdown $grace_period_seconds $target' TERM INT HUP
- sleep 2
- echo "waiting for job to start..."
- timeout 10s ./wait_for_job.sh $pattern
- target_pid=$(pgrep -f $pattern -l | grep -v 'job_killer.sh' | grep -v 'wait_for_job.sh' | grep -v 'grep' | awk '{ printf "%d ", $1 }' | sort)
- target_pid_name=$(pgrep -f $pattern -l | grep -v 'job_killer.sh' | grep -v 'wait_for_job.sh' | grep -v 'grep')
- if [ -n "$target_pid" ]; then
- echo "targeting pids $target_pid matched by $target_pid_name"
- # schedule hard kill after global timeout
- is_global_shutdown=""
- (sleep ${global_timeout}; echo "triggering global shutdown" && is_global_shutdown="true" && graceful_shutdown $grace_period_seconds $target || true) &
- global_killer=${!}
-
- tail --pid=$target_pid -f /dev/null &
- child=$!
- wait "$child"
- if [ -z "$is_global_shutdown" ]; then
- # cancel hard kill timer
- sleep 0.1 && kill -9 ${global_killer} 2>/dev/null || true
- graceful_shutdown $grace_period_seconds $target
- fi
- else
- echo "no process could be targeted within 10s, initiating shutdown"
- if [ -n "$sidecar" ]; then
- echo "killing sidecar command: $sidecar"
- ./sidecar_killer.sh $sidecar
- fi
- fi
|