# 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 : 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 } ''