mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-30 04:31:11 +08:00
64 lines
2.2 KiB
Bash
64 lines
2.2 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# Fork from the current Bash state: an external `bash -c` would lose private
|
|
# before-hook variables, arrays and functions used by sourced Shell scripts.
|
|
run_task_command() {
|
|
local timeout_seconds
|
|
if [[ -z ${command_timeout_time:-} ]]; then
|
|
"$@"
|
|
return $?
|
|
fi
|
|
timeout_seconds=$(awk -v value="$command_timeout_time" 'BEGIN {
|
|
if (value !~ /^([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][+-]?[0-9]+)?[smhd]?$/) exit 1
|
|
unit = substr(value, length(value), 1)
|
|
factor = unit == "d" ? 86400 : unit == "h" ? 3600 : unit == "m" ? 60 : 1
|
|
printf "%.9f", (value + 0) * factor
|
|
}') || { printf 'Invalid task timeout: %s\n' "$command_timeout_time" >&2; return 125; }
|
|
if [[ $timeout_seconds == '0.000000000' ]]; then
|
|
"$@"
|
|
return $?
|
|
fi
|
|
(
|
|
timeout_dir=$(mktemp -d "${TMPDIR:-/tmp}/ql-task-timeout.XXXXXXXX") || exit 125
|
|
# Both children get private process groups. The timer and the wrapper must
|
|
# survive terminating the task, and descendants must not outlive a timeout.
|
|
set -m
|
|
( set +m; "$@" ) <&0 &
|
|
timeout_worker=$!
|
|
(
|
|
set +m
|
|
: > "$timeout_dir/ready"
|
|
sleep "$timeout_seconds" || exit 125
|
|
: > "$timeout_dir/expired"
|
|
kill -TERM -- "-$timeout_worker" 2>/dev/null || :
|
|
sleep 0.5
|
|
kill -KILL -- "-$timeout_worker" 2>/dev/null || :
|
|
) &
|
|
timeout_watcher=$!
|
|
set +m
|
|
trap 'kill -KILL -- "-$timeout_watcher" 2>/dev/null || :
|
|
if kill -TERM -- "-$timeout_worker" 2>/dev/null; then sleep 0.1; fi
|
|
kill -KILL -- "-$timeout_worker" 2>/dev/null || :
|
|
wait "$timeout_worker" 2>/dev/null || :
|
|
wait "$timeout_watcher" 2>/dev/null || :
|
|
rm -rf -- "$timeout_dir"' EXIT
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
trap 'exit 129' HUP
|
|
trap 'exit 131' QUIT
|
|
# Do not clean up a timer whose process group has not initialized yet.
|
|
while [[ ! -f "$timeout_dir/ready" ]]; do
|
|
kill -0 "$timeout_watcher" 2>/dev/null || exit 125
|
|
sleep 0.001
|
|
done
|
|
wait "$timeout_worker"
|
|
timeout_code=$?
|
|
if [[ -f "$timeout_dir/expired" ]]; then
|
|
# Let the timer finish escalation even if the task leader exited first.
|
|
wait "$timeout_watcher" 2>/dev/null || :
|
|
exit 124
|
|
fi
|
|
exit "$timeout_code"
|
|
)
|
|
}
|