Repository navigation
Worker Liveness Probe (5-min) #1008
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Worker Liveness Probe (5-min) | |
| # GAP-443 — external GHA scheduler for the Fly worker liveness probe. | |
| # | |
| # Background: Vercel Hobby tier crons run at most daily, and the one daily | |
| # slot is already consumed by `dispatch.ts` (~14 billing/entitlement jobs). | |
| # The liveness probe needs a sub-daily cadence, so (same rationale as | |
| # GAP-142's reconciliation-crons.yml) this workflow drives it externally | |
| # every 5 minutes - free on a public repo, no Vercel Pro required. | |
| # | |
| # The probe route (apps/server/src/routes/cron/worker-liveness.ts) reads the | |
| # actual worker URL from REVEALUI_WORKER_HEALTH_URL, an env var on the | |
| # api project. This workflow never sees or prints that URL. It calls the cron | |
| # origin (REVEALUI_CRON_ORIGIN, default https://revealui-api.vercel.app) and | |
| # reports the probe's healthy/status result, keeping the worker hostname out | |
| # of the public repo and out of Actions logs. | |
| on: | |
| # Schedule re-enabled 2026-07-28 after GAP-455 green proof: | |
| # run 30400804458 returned {"healthy":true,"status":200,"probe":4} with the | |
| # #2267 classifier on production. Error buckets + guard-unavailable path | |
| # ship on main; schedule was the remaining ops gate for the green case. | |
| # Red-path proof (genuinely down worker) remains on GAP-455 before close. | |
| schedule: | |
| # Every 5 minutes (GitHub's minimum granularity). UTC. Scheduled runs can | |
| # be delayed 5-15 min during high GHA load, so actual cadence is | |
| # "approximately every 5 minutes," not exact - acceptable for a | |
| # liveness backstop. | |
| - cron: '*/5 * * * *' | |
| workflow_dispatch: | |
| inputs: | |
| reason: | |
| description: 'Reason for manual run' | |
| required: false | |
| default: 'manual ops trigger' | |
| # This job only GETs a public API endpoint with a bearer secret header; it | |
| # never uses GITHUB_TOKEN. Grant it nothing. | |
| permissions: {} | |
| jobs: | |
| worker-liveness: | |
| name: worker-liveness | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: GET /api/cron/worker-liveness | |
| env: | |
| API_URL: ${{ vars.REVEALUI_CRON_ORIGIN || 'https://revealui-api.vercel.app' }} | |
| CRON_SECRET: ${{ secrets.REVEALUI_CRON_SECRET }} | |
| run: | | |
| if [[ -z "$CRON_SECRET" ]]; then | |
| echo "::error::REVEALUI_CRON_SECRET secret not set" | |
| exit 1 | |
| fi | |
| response=$(curl -sS \ | |
| -H "X-Cron-Secret: $CRON_SECRET" \ | |
| -w "\nHTTP_STATUS:%{http_code}" \ | |
| "$API_URL/api/cron/worker-liveness" || true) | |
| status=$(echo "$response" | grep "HTTP_STATUS:" | cut -d: -f2) | |
| body=$(echo "$response" | sed '/HTTP_STATUS:/d') | |
| echo "Status: $status" | |
| echo "Body: $body" | |
| if [[ "$status" != "200" ]]; then | |
| echo "::error::worker-liveness returned $status (non-200) — worker unhealthy, unreachable, or misconfigured" | |
| exit 1 | |
| fi |