Skip to content

Commit e74fadb

Browse files
Toilalclaude
andauthored
ci: retry the gh-pages publish with backoff on transient failures (#81)
* ci: retry the gh-pages publish up to 3× on transient failures GitHub's auto "pages build and deployment" occasionally fails with "Deployment failed, try again later." when concurrent gh-pages pushes race, leaving the site stuck on the previous build. Add a composite action that, after each zensical deploy, waits for that deployment and reruns it up to three times until it succeeds. Wire it into the main, develop and preview workflows and grant them actions: write so they can rerun the run. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgcYQy7Mnh2afkmSg295uU * ci: add progressive backoff and raise pages publish retries to 5 Under concurrent multi-repo Pages deploys, GitHub throttles at the account level and reruns fired seconds apart still fail. Wait a growing delay (30/60/90/120s) before each rerun and allow up to 5 attempts, so the retry absorbs the throttling window instead of exhausting itself immediately. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgcYQy7Mnh2afkmSg295uU --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e27ff85 commit e74fadb

4 files changed

Lines changed: 94 additions & 0 deletions

File tree

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: Ensure Pages published
2+
description: >-
3+
Wait for GitHub's auto "pages build and deployment" of the current gh-pages
4+
HEAD and rerun it (with backoff) if it fails with a transient error.
5+
6+
runs:
7+
using: composite
8+
steps:
9+
- shell: bash
10+
env:
11+
GH_TOKEN: ${{ github.token }}
12+
REPO: ${{ github.repository }}
13+
ATTEMPTS: "5"
14+
run: |
15+
set -euo pipefail
16+
17+
target_sha="$(gh api "repos/$REPO/branches/gh-pages" --jq '.commit.sha')"
18+
echo "Ensuring Pages is published for gh-pages@$target_sha"
19+
20+
find_run() {
21+
gh run list --repo "$REPO" --workflow "pages-build-deployment" \
22+
--commit "$target_sha" --limit 1 \
23+
--json databaseId,status,conclusion \
24+
--jq '.[0] // empty | "\(.databaseId) \(.status) \(.conclusion // "")"' 2>/dev/null || true
25+
}
26+
27+
# Block until a run for this SHA reaches "completed"; echo "id conclusion".
28+
await_completed() {
29+
for _ in $(seq 1 60); do
30+
local info id status conclusion
31+
info="$(find_run)"
32+
id="$(printf '%s' "$info" | awk '{print $1}')"
33+
status="$(printf '%s' "$info" | awk '{print $2}')"
34+
conclusion="$(printf '%s' "$info" | awk '{print $3}')"
35+
if [ -n "$id" ] && [ "$status" = "completed" ]; then
36+
printf '%s %s\n' "$id" "$conclusion"
37+
return 0
38+
fi
39+
sleep 10
40+
done
41+
return 1
42+
}
43+
44+
for attempt in $(seq 1 "$ATTEMPTS"); do
45+
echo "::group::Pages publish check (attempt $attempt/$ATTEMPTS)"
46+
if ! result="$(await_completed)"; then
47+
echo "Timed out waiting for the pages-build-deployment run." >&2
48+
echo "::endgroup::"
49+
exit 1
50+
fi
51+
run_id="${result%% *}"
52+
conclusion="${result##* }"
53+
echo "pages-build-deployment run $run_id -> $conclusion"
54+
echo "::endgroup::"
55+
56+
if [ "$conclusion" = "success" ]; then
57+
echo "Pages published for gh-pages@$target_sha."
58+
exit 0
59+
fi
60+
61+
if [ "$attempt" -lt "$ATTEMPTS" ]; then
62+
# Progressive backoff: transient failures are usually account-level
63+
# Pages throttling under concurrent deploys — give it room to clear.
64+
backoff=$((attempt * 30))
65+
echo "Transient failure; waiting ${backoff}s before rerunning run $run_id…"
66+
sleep "$backoff"
67+
gh run rerun "$run_id" --repo "$REPO" || true
68+
# Let the rerun leave the "completed" state before we poll again.
69+
for _ in $(seq 1 12); do
70+
status="$(find_run | awk '{print $2}')"
71+
[ "$status" != "completed" ] && break
72+
sleep 5
73+
done
74+
fi
75+
done
76+
77+
echo "Pages deployment still failing after $ATTEMPTS attempts for gh-pages@$target_sha." >&2
78+
exit 1

.github/workflows/zensical-develop.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ on:
99
concurrency:
1010
group: gh-pages-develop
1111
cancel-in-progress: true
12+
permissions:
13+
contents: write
14+
actions: write
1215
jobs:
1316
deploy:
1417
runs-on: ubuntu-latest
@@ -35,3 +38,6 @@ jobs:
3538
# Publish the develop build under /dev/ without touching the stable site at the root.
3639
target-folder: dev
3740
clean: true
41+
42+
- name: Ensure Pages published (retry ×3)
43+
uses: ./.github/actions/ensure-pages-published

.github/workflows/zensical-preview.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ concurrency:
1111
cancel-in-progress: true
1212
permissions:
1313
contents: write
14+
actions: write
1415
jobs:
1516
deploy:
1617
# Same-repo docs/* PRs only: fork PRs get a read-only token and cannot push to gh-pages.
@@ -49,6 +50,9 @@ jobs:
4950
target-folder: preview/${{ steps.slug.outputs.name }}
5051
clean: true
5152

53+
- name: Ensure Pages published (retry ×3)
54+
uses: ./.github/actions/ensure-pages-published
55+
5256
cleanup:
5357
# When a docs/* PR is merged or closed, remove its preview folder.
5458
if: >-

.github/workflows/zensical.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ on:
99
concurrency:
1010
group: gh-pages-main
1111
cancel-in-progress: false
12+
permissions:
13+
contents: write
14+
actions: write
1215
jobs:
1316
deploy:
1417
runs-on: ubuntu-latest
@@ -38,3 +41,6 @@ jobs:
3841
clean-exclude: |
3942
dev
4043
preview
44+
45+
- name: Ensure Pages published (retry ×3)
46+
uses: ./.github/actions/ensure-pages-published

0 commit comments

Comments
 (0)