@@ -114,11 +114,12 @@ jobs:
114114 wait_healthy() {
115115 # Caddy keeps a connection pool to app:8000 with retries, so
116116 # users see a brief latency bump (not 502) during the swap.
117+ [ -n "$1" ] || { echo "::error::wait_healthy: missing container name"; return 1; }
117118 status=""
118- for i in 1 2 3 4 5 6 7 8; do
119- status=$(docker inspect spoo_app --format '{{.State.Health.Status}}' 2>/dev/null || echo "missing")
119+ for i in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
120+ status=$(docker inspect "$1" --format '{{.State.Health.Status}}' 2>/dev/null || echo "missing")
120121 [ "$status" = "healthy" ] && return 0
121- echo "app $status, retry $i"; sleep 3
122+ echo "$1 $status, retry $i"; sleep 3
122123 done
123124 return 1
124125 }
@@ -127,7 +128,7 @@ jobs:
127128 docker compose --env-file .env -f docker-compose.prod.yml pull app
128129 docker compose --env-file .env -f docker-compose.prod.yml up -d --no-deps app
129130
130- if ! wait_healthy; then
131+ if ! wait_healthy spoo_app ; then
131132 echo "::error::app failed to reach healthy on ${IMAGE_TAG} (last status: $status)"
132133 # diagnostics must never abort the rollback below (set -e)
133134 docker compose --env-file .env -f docker-compose.prod.yml logs --tail=100 app || true
@@ -136,7 +137,29 @@ jobs:
136137 set_tag "${PREV_TAG}"
137138 docker compose --env-file .env -f docker-compose.prod.yml pull app || true
138139 docker compose --env-file .env -f docker-compose.prod.yml up -d --no-deps app
139- if wait_healthy; then
140+ if wait_healthy spoo_app; then
141+ echo "::warning::rolled back — prod is healthy on previous image ${PREV_TAG}"
142+ else
143+ echo "::error::rollback to ${PREV_TAG} also unhealthy — manual intervention needed"
144+ fi
145+ fi
146+ exit 1
147+ fi
148+
149+ # The click worker runs the SAME image (shared wire contract with
150+ # the app) — swap it only after the app is confirmed healthy, so
151+ # an app rollback leaves the worker untouched on the old pair.
152+ docker compose --env-file .env -f docker-compose.prod.yml up -d --no-deps click-worker
153+
154+ if ! wait_healthy spoo_click_worker; then
155+ echo "::error::click worker failed to reach healthy on ${IMAGE_TAG} (last status: $status)"
156+ docker compose --env-file .env -f docker-compose.prod.yml logs --tail=100 click-worker || true
157+ if [ -n "$PREV_TAG" ] && [ "$PREV_TAG" != "$IMAGE_TAG" ]; then
158+ echo "rolling back app + worker to ${PREV_TAG}"
159+ set_tag "${PREV_TAG}"
160+ docker compose --env-file .env -f docker-compose.prod.yml pull app click-worker || true
161+ docker compose --env-file .env -f docker-compose.prod.yml up -d --no-deps app click-worker
162+ if wait_healthy spoo_app && wait_healthy spoo_click_worker; then
140163 echo "::warning::rolled back — prod is healthy on previous image ${PREV_TAG}"
141164 else
142165 echo "::error::rollback to ${PREV_TAG} also unhealthy — manual intervention needed"
0 commit comments