In the past I used pid-files to guarantee race-condition safe execution of scripts. But this had the downside, that the pid-file was not deleted if the kernel killed the script somehow. So sometimes manual interaction was needed (remove the pid file, killing some sub processes).
Finally I came up to a solution which checks if a script is running by using
pgrep
and kills really old processes that shouldn't exist anymore:
while read -r pid cmd; do
# check if pid or parent pid belong to current script execution
if [[ $pid == "$$" ]] || [[ $(ps -o ppid= -p "$pid" | xargs) == "$$" ]]; then
continue
fi
# avoid re-execution of script within 12 hours (43200 seconds)
if [[ $(date +%s --d="now - $( stat -c%X "/proc/$pid" ) seconds") -lt 43200 ]]; then
echo "Error: Script is already running!"
exit
fi
# kill outdated script executions
if kill -9 "$pid"; then
echo "Warning: Outdated script execution ($pid) has been killed!"
fi
done /dev/null; then
continue
fi
# verify that pid is part of the list ("pstree --show-parents" returns list, even pid does not exist https://github.com/acg/psmisc/issues/5)
if ! echo "$pid_list" | grep -F "($pid)" >/dev/null; then
continue # process does not exist anymore
fi
# obtain age of pid
pid_time=$( stat -c%X "/proc/$pid" 2>/dev/null )
if [[ ! $pid_time ]]; then
continue # process does not exist anymore
fi
# kill outdated script executions (older than 12 hours / 43200 seconds)
if [[ $(date +%s --d="now - $pid_time seconds") -gt 43200 ]]; then
if kill -9 "$pid"; then
echo "Warning: Outdated script execution ($pid) has been killed!"
fi
# we are facing a race condition
else
echo "Error: Script is already running!"
exit 1
fi
done < <(pgrep -f "^/bin/bash $script_path") # obtain pids that belong to this script
Asked by mgutt
(547 rep)
Apr 3, 2023, 11:50 PM
Last activity: Apr 18, 2023, 07:35 AM
Last activity: Apr 18, 2023, 07:35 AM