Skip to content

Scheduled Health Check #902

Scheduled Health Check

Scheduled Health Check #902

name: Scheduled Health Check
on:
schedule:
- cron: "0 * * * *" # Every hour
workflow_dispatch:
env:
NODE_VERSION: "20"
jobs:
health-check-production:
name: health-production
runs-on: ubuntu-latest
steps:
- name: Check production login page
run: |
URL="${{ secrets.PRODUCTION_APP_URL }}"
if [ -z "$URL" ]; then
echo "[SKIP] PRODUCTION_APP_URL not configured"
exit 0
fi
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${URL}/login" --max-time 15)
if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "302" ] || [ "$HTTP_STATUS" = "307" ]; then
echo "[OK] Production login page: HTTP ${HTTP_STATUS}"
else
echo "[FAIL] Production login page: HTTP ${HTTP_STATUS}"
exit 1
fi
- name: Check production health endpoint
run: |
URL="${{ secrets.PRODUCTION_APP_URL }}"
if [ -z "$URL" ]; then
echo "[SKIP] PRODUCTION_APP_URL not configured"
exit 0
fi
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${URL}/api/health" --max-time 15)
if [ "$HTTP_STATUS" = "200" ]; then
echo "[OK] Production health endpoint: HTTP ${HTTP_STATUS}"
else
echo "[FAIL] Production health endpoint: HTTP ${HTTP_STATUS}"
exit 1
fi
- name: Check production PWA manifest
run: |
URL="${{ secrets.PRODUCTION_APP_URL }}"
if [ -z "$URL" ]; then
echo "[SKIP] PRODUCTION_APP_URL not configured"
exit 0
fi
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${URL}/manifest.json" --max-time 15)
if [ "$HTTP_STATUS" = "200" ]; then
echo "[OK] Production PWA manifest: HTTP ${HTTP_STATUS}"
else
echo "[WARN] Production PWA manifest: HTTP ${HTTP_STATUS} (non-blocking)"
fi
- name: Check production auth guards
run: |
URL="${{ secrets.PRODUCTION_APP_URL }}"
if [ -z "$URL" ]; then
echo "[SKIP] PRODUCTION_APP_URL not configured"
exit 0
fi
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${URL}/api/leads" --max-time 15)
if [ "$HTTP_STATUS" = "401" ] || [ "$HTTP_STATUS" = "307" ] || [ "$HTTP_STATUS" = "302" ]; then
echo "[OK] Production auth guards: HTTP ${HTTP_STATUS}"
else
echo "[WARN] Production auth guards: HTTP ${HTTP_STATUS} (expected 401 or 307)"
fi
health-check-staging:
name: health-staging
runs-on: ubuntu-latest
steps:
- name: Check staging login page
run: |
URL="${{ secrets.STAGING_APP_URL }}"
if [ -z "$URL" ]; then
echo "[SKIP] STAGING_APP_URL not configured"
exit 0
fi
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${URL}/login" --max-time 15)
if [ "$HTTP_STATUS" = "200" ] || [ "$HTTP_STATUS" = "302" ] || [ "$HTTP_STATUS" = "307" ]; then
echo "[OK] Staging login page: HTTP ${HTTP_STATUS}"
else
echo "[FAIL] Staging login page: HTTP ${HTTP_STATUS}"
exit 1
fi
- name: Check staging health endpoint
run: |
URL="${{ secrets.STAGING_APP_URL }}"
if [ -z "$URL" ]; then
echo "[SKIP] STAGING_APP_URL not configured"
exit 0
fi
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${URL}/api/health" --max-time 15)
if [ "$HTTP_STATUS" = "200" ]; then
echo "[OK] Staging health endpoint: HTTP ${HTTP_STATUS}"
else
echo "[WARN] Staging health endpoint: HTTP ${HTTP_STATUS} (non-blocking)"
fi
cron-job-liveness:
name: cron-liveness
runs-on: ubuntu-latest
steps:
- name: Check daily digest liveness
run: |
URL="${{ secrets.PRODUCTION_APP_URL }}"
if [ -z "$URL" ]; then
echo "[SKIP] PRODUCTION_APP_URL not configured"
exit 0
fi
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${URL}/api/cron/daily-digest" --max-time 15)
if [ "$HTTP_STATUS" = "401" ] || [ "$HTTP_STATUS" = "200" ]; then
echo "[OK] Cron endpoint reachable: HTTP ${HTTP_STATUS}"
else
echo "[WARN] Cron endpoint returned HTTP ${HTTP_STATUS} (non-blocking)"
fi
alert-on-failure:
name: alert-on-failure
runs-on: ubuntu-latest
needs: [health-check-production, health-check-staging, cron-job-liveness]
if: failure()
steps:
- name: Create incident issue
uses: actions/github-script@v7
with:
script: |
const title = `[INCIDENT] Health Check Failure — ${new Date().toISOString().split('T')[0]}`;
const body = `## Health Check Failure Detected
**Time:** ${new Date().toISOString()}
**Workflow:** ${{ github.workflow }}
**Run:** ${{ github.run_id }}
### Failed Jobs
- Production Health: ${{ needs.health-check-production.result }}
- Staging Health: ${{ needs.health-check-staging.result }}
- Cron Liveness: ${{ needs.cron-job-liveness.result }}
### Required Actions
1. Check Vercel deployment status
2. Verify Supabase connectivity
3. Review error logs
**Auto-created by:** scheduled-health-check workflow`;
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: title,
body: body,
labels: ['incident', 'automated']
});