A download that hangs ends within its step and starts again¶
- Status: accepted
- Date: 2026-10-24
Context¶
Since every step that installs, builds or downloads ends after five minutes (0021), a download that hangs no longer holds a pull request for half an hour, but it still fails its job. The flaky-test bot runs such a job once more (0014) and writes it into issue 179. From 2026-10-14 to 2026-10-23, it wrote down eight such jobs of the Variants, seven of them in three kinds:
- The build of the website hung four times until its step ran out of its five minutes, after the last font that the privacy plugin of Material downloaded. The privacy plugin gives each download 5 seconds, but the social plugin downloads the fonts of the preview cards from Google Fonts with no time limit at all.
.github/mkdocs_blueprint.pyalready tried a download of both plugins again after an error of the network (0011), but a server that stops answering raises no error: the attempt waits without end. The Docs workflow of every repository builds its website with the same plugins. - The download of uv hung in two legs at once, on
releases.astral.sh, whichastral-sh/setup-uvdownloads uv from, with no time limit of its own; the step usually takes three seconds. - Docker Hub answered the pull of an image with a 502, and
docker runexited with 125 before the lint of the workflows ran.
The eighth job hung in the pre-step of harden-runner, before any step of the workflow ran, which no setting of a step bounds.
Options¶
- Leave it to the flaky-test bot. Every hang costs a job of up to ten minutes again, and the pull request waits for it.
- Run the whole step again when it fails, in a loop around each command. A loop around
mkdocs buildbuilds everything again for one font; GitHub has no setting to run a step of an action, such assetup-uv, again. - A time limit for each download, well within its step, and a second attempt of that download alone: in the hooks of the website for every download of the plugins, a second
setup-uvfrom another server when the first doesn't end within two minutes, and adockerin front of the runner's that starts a container again when the pull of its image failed.
Decision¶
Option 3.
- The website: a download of the privacy or the social plugin that names no time limit gets 10 seconds to connect and 30 for each next part of the file (
TIMEOUTof.github/mkdocs_blueprint.py); the privacy plugin keeps its own 5 seconds. A download that runs out of its time is tried again like one that failed, three times in all, which ends within about two minutes for a server that no longer answers. It reaches the website of every repository with the next release. - uv: the Variants set uv up with
continue-on-errorand two minutes; only when that attempt fails or runs out of its time, a second one sets the same uv up withdownload-from-astral-mirror: false, from the releases of uv on GitHub. The job passes with either, and Renovate moves the version of both. - Images: a step of the Variants puts a
dockerin front of the runner's on thePATH, for every step after it and forscripts/check.sh. Whendocker runexits with 125, Docker's own code for a container that it couldn't start, it starts the container again after 10 and then 20 seconds, with a warning; every other exit code, that of a check in the container among them, and every other command it passes on at once.
Consequences¶
A font server that stops answering costs a build of the website about two minutes at most instead of its step, and what fails all its attempts still fails the step, with the error of the last one, for the flaky-test bot. A hang of the download of uv costs two minutes instead of the job. A container that Docker couldn't start for another reason, such as a wrong option, also starts three times before its step fails, 30 seconds later. The other workflows that set uv up keep one attempt; they adopt the second one when a hang of uv shows up there as well. The pre-step of harden-runner stays bounded only by the time limit of its job.