diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index aca5c40..01f8de9 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -93,6 +93,15 @@ jobs: # Update compose files + mosquitto config git pull origin main + # Deploy THIS commit's images, not :latest. Overlapping runs are + # normal here, and with :latest whichever finishes last wins for + # both -- run 544 asserted its own SHA and found run 545's build + # already serving. compose already supports ${TAG:-latest}, so + # pinning makes each deploy deterministic and a rollback just a + # different tag. A later manual `up -d` on the VM without TAG set + # still falls back to :latest, which is the intended escape hatch. + export TAG=${{ gitea.sha }} + # Pull pre-built images and restart (no build on the VM). # # The retry is not defensive padding: this exact step failed fifteen @@ -114,9 +123,19 @@ jobs: - name: Health check run: | - sleep 20 - BODY=$(curl -fsS https://api.${{ secrets.DRB_DOMAIN }}/health) || { - echo "Health check failed: /health did not respond"; exit 1; } + # Poll rather than sleep-once: the container has to finish starting, + # and a fixed sleep is either too short (flaky red) or wastes time on + # every deploy. A health check that cries wolf gets ignored, which is + # the failure mode this whole job exists to prevent. + BODY="" + for _ in $(seq 1 20); do + sleep 5 + BODY=$(curl -fsS https://api.${{ secrets.DRB_DOMAIN }}/health) || continue + case "$BODY" in *"${{ gitea.sha }}"*) break ;; esac + done + if [ -z "$BODY" ]; then + echo "Health check failed: /health never responded"; exit 1 + fi echo "$BODY" # Liveness alone is not enough. A deploy can report success while the