ci: pin Docker Deploy to a single app container IP
CI / Lint (push) Successful in 3m27s
CI / Architecture Guardrails (push) Successful in 4m31s
CI / Assistant Split Regression (push) Successful in 5m32s
CI / Typecheck (push) Successful in 6m24s
CI / Unit Tests (push) Successful in 8m31s
CI / Build (push) Successful in 7m35s
CI / E2E Tests (push) Successful in 7m48s
Nightly Security / Dependency Audit (push) Successful in 1m42s
CI / Fresh-Linux Docker Deploy (push) Failing after 9m57s
CI / Release Images (push) Has been skipped
CI / Lint (push) Successful in 3m27s
CI / Architecture Guardrails (push) Successful in 4m31s
CI / Assistant Split Regression (push) Successful in 5m32s
CI / Typecheck (push) Successful in 6m24s
CI / Unit Tests (push) Successful in 8m31s
CI / Build (push) Successful in 7m35s
CI / E2E Tests (push) Successful in 7m48s
Nightly Security / Dependency Audit (push) Successful in 1m42s
CI / Fresh-Linux Docker Deploy (push) Failing after 9m57s
CI / Release Images (push) Has been skipped
Smoke test #2 kept hitting ERR_CONNECTION_REFUSED on the root path even though curl warm-ups of the same path succeeded. Root cause is the same split-brain bug we just fixed for e2epg: the 'app' hostname on the shared gitea_gitea network resolves to multiple IPs (leftover containers from concurrent runs), and curl vs Chromium picked different ones. Probe each resolved IP for /api/health, pin the winner as APP_BASE_URL via GITHUB_ENV, and route health check, warm-up, and the Playwright smoke run through that explicit IP. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+28
-14
@@ -484,23 +484,39 @@ jobs:
|
||||
- name: Build and start app (full profile)
|
||||
run: docker compose -f docker-compose.yml -f docker-compose.ci.yml --profile full up -d --build app
|
||||
|
||||
- name: Wait for /api/health (up to 3 minutes)
|
||||
# docker-compose.ci.yml attaches app/postgres/redis to gitea_gitea so the
|
||||
# act_runner job container can reach them by compose service name.
|
||||
- name: Resolve and pin app IP
|
||||
# 'app' hostname collides on shared gitea_gitea network — same split
|
||||
# -brain as e2epg. Smoke test #2 hit ERR_CONNECTION_REFUSED even
|
||||
# after both warm-ups returned the expected codes, because curl and
|
||||
# Playwright-launched Chromium picked different IPs from the DNS set.
|
||||
# Probe each resolved IP for /api/health and pin the winner as
|
||||
# APP_BASE_URL so every subsequent step (wait, warm-up, smoke run)
|
||||
# hits the same container.
|
||||
run: |
|
||||
for i in $(seq 1 36); do
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://app:3100/api/health || echo "000")
|
||||
echo "Attempt $i: HTTP $STATUS"
|
||||
if [ "$STATUS" = "200" ]; then exit 0; fi
|
||||
IPS=$(getent hosts app | awk '{print $1}')
|
||||
if [ -n "$IPS" ]; then
|
||||
for ip in $IPS; do
|
||||
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "http://$ip:3100/api/health" || echo "000")
|
||||
echo "Attempt $i: $ip -> HTTP $CODE"
|
||||
if [ "$CODE" = "200" ]; then
|
||||
echo "APP_IP=$ip" >> "$GITHUB_ENV"
|
||||
echo "APP_BASE_URL=http://$ip:3100" >> "$GITHUB_ENV"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "Attempt $i: 'app' not yet in DNS"
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
echo "Health check timed out"
|
||||
echo "No reachable app:3100 found"
|
||||
docker compose -f docker-compose.yml -f docker-compose.ci.yml logs app --tail=50
|
||||
exit 1
|
||||
|
||||
- name: Verify health response contains status ok
|
||||
run: |
|
||||
BODY=$(curl -sf http://app:3100/api/health)
|
||||
BODY=$(curl -sf "$APP_BASE_URL/api/health")
|
||||
echo "$BODY"
|
||||
echo "$BODY" | grep '"status":"ok"'
|
||||
|
||||
@@ -519,7 +535,7 @@ jobs:
|
||||
local path="$1"
|
||||
local expect="$2"
|
||||
for i in $(seq 1 24); do
|
||||
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "http://app:3100${path}" || echo "000")
|
||||
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "${APP_BASE_URL}${path}" || echo "000")
|
||||
echo "Warm-up ${path} $i: HTTP $CODE"
|
||||
if [ "$CODE" = "$expect" ]; then return 0; fi
|
||||
sleep 5
|
||||
@@ -572,11 +588,9 @@ jobs:
|
||||
/tmp/pw-install/node_modules/.bin/playwright install chromium --with-deps
|
||||
|
||||
- name: Run smoke tests
|
||||
env:
|
||||
# App runs on the compose network; act_runner job is on gitea_gitea
|
||||
# (docker-compose.ci.yml attaches services to both). Override baseURL.
|
||||
PLAYWRIGHT_BASE_URL: http://app:3100
|
||||
run: /tmp/pw-install/node_modules/.bin/playwright test --config apps/web/playwright.ci.config.ts
|
||||
# Use the pinned APP_BASE_URL (explicit IP) so Chromium hits the same
|
||||
# container as the warm-up probes.
|
||||
run: PLAYWRIGHT_BASE_URL="$APP_BASE_URL" /tmp/pw-install/node_modules/.bin/playwright test --config apps/web/playwright.ci.config.ts
|
||||
|
||||
- name: Upload Playwright report
|
||||
if: failure()
|
||||
|
||||
Reference in New Issue
Block a user