38 lines
1.4 KiB
Nix
38 lines
1.4 KiB
Nix
# Shared shell step for a oneshot that fetches over the network and that other
|
|
# units `Requires=`. `retry_in_job` repeats the fetch inside the unit's own
|
|
# start job, so a unit ordered `After=` it waits for the fetch to succeed. A
|
|
# unit that exits non-zero ends its job as `failed` and fails every `Requires=`
|
|
# dependent with `dependency`; a dependent whose start job failed is not
|
|
# started again when the retry succeeds, so ./store-retry.nix cannot cover
|
|
# this case.
|
|
#
|
|
# The retry stops at the budget and returns non-zero, so the unit still fails
|
|
# closed. Set the unit's `TimeoutStartSec` above the budget, or systemd kills
|
|
# the job before the helper gives up.
|
|
#
|
|
# Pure function — NOT a NixOS module. Call it from a unit's `script`:
|
|
#
|
|
# retryInJob = import ../host-modules/lib/retry-in-job.nix { };
|
|
# script = ''
|
|
# ${retryInJob}
|
|
# if ! retry_in_job 840 fetch; then exit 1; fi
|
|
# '';
|
|
{ }:
|
|
''
|
|
# retry_in_job <budget-seconds> <command…>: run the command until it
|
|
# succeeds, waiting 2s, doubling to at most 60s between attempts. Returns 1
|
|
# once another wait would pass the budget.
|
|
retry_in_job() {
|
|
local rc delay=2 deadline=$((SECONDS + $1))
|
|
shift
|
|
until "$@"; do
|
|
rc=$?
|
|
if [ $((SECONDS + delay)) -gt "$deadline" ]; then
|
|
return 1
|
|
fi
|
|
echo "the attempt failed with exit status $rc; retrying in $delay seconds." >&2
|
|
sleep "$delay"
|
|
delay=$((delay * 2 > 60 ? 60 : delay * 2))
|
|
done
|
|
}
|
|
''
|