Skip to content

Health Checks

Health Checks #227

Workflow file for this run

name: Health Checks
on:
schedule:
# 3시간마다 quick 체크 실행
- cron: '10 0,3,6,9,12,18,21 * * *'
# 한국시간 00:10 = UTC 15:10, 하루 1회 full fresh 체크 실행
- cron: '10 15 * * *'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: health-checks-${{ github.ref }}
cancel-in-progress: false
jobs:
health-checks:
runs-on: ubuntu-latest
name: Service health checks
steps:
- name: Run health checks
env:
HEALTH_CHECK_SECRET: ${{ secrets.HEALTH_CHECK_SECRET }}
HEALTH_CHECK_URL: ${{ vars.HEALTH_CHECK_URL || 'https://mcp.aka.page' }}
HEALTH_CHECK_SCHEDULE: ${{ github.event.schedule }}
run: |
if [ -z "${HEALTH_CHECK_SECRET}" ]; then
echo "HEALTH_CHECK_SECRET is not set"
exit 1
fi
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ] || [ "${HEALTH_CHECK_SCHEDULE:-}" = "10 15 * * *" ]; then
HEALTH_CHECK_ENDPOINT="${HEALTH_CHECK_URL}/api/health/checks?mode=full&fresh=true&includeSamples=true&timeoutMs=20000&slowThresholdMs=9000"
HEALTH_CHECK_FORCE_FRESH="true"
else
HEALTH_CHECK_ENDPOINT="${HEALTH_CHECK_URL}/api/health/checks?mode=quick&timeoutMs=5000&slowThresholdMs=3000"
HEALTH_CHECK_FORCE_FRESH="false"
fi
run_health_check() {
curl -fsS \
-H "Authorization: Bearer ${HEALTH_CHECK_SECRET}" \
-H "x-health-check-force-fresh: ${HEALTH_CHECK_FORCE_FRESH}" \
"${HEALTH_CHECK_ENDPOINT}" \
-o health-checks.json
node <<'NODE'
const fs = require('node:fs');
const payload = JSON.parse(fs.readFileSync('health-checks.json', 'utf8'));
const failedChecks = (payload.checks || []).filter((check) => check.status === 'fail');
const degradedChecks = (payload.checks || []).filter((check) => check.status === 'degraded');
const lines = [...failedChecks, ...degradedChecks].map((check) => {
const sample = check.sample?.first ? ` sample=${check.sample.first}` : '';
return `${check.id}:${check.status}:${check.message}${sample}`;
});
const runUrl = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`;
const summary = [
`status=${payload.status || 'unknown'}`,
`failed=${failedChecks.length}`,
`degraded=${degradedChecks.length}`,
`run=${runUrl}`,
lines.slice(0, 6).join(' | '),
].filter(Boolean).join(' ');
fs.writeFileSync('health-check-summary.txt', summary);
console.log(summary);
if (failedChecks.length > 0 || payload.status === 'fail') {
process.exitCode = 1;
}
NODE
}
if ! run_health_check; then
echo "Health check failed on attempt 1; retrying once"
sleep 10
run_health_check
fi
- name: Notify health failure
if: failure()
env:
MOSHI_WEBHOOK_TOKEN: ${{ secrets.MOSHI_WEBHOOK_TOKEN }}
run: |
if [ -z "${MOSHI_WEBHOOK_TOKEN}" ]; then
echo "MOSHI_WEBHOOK_TOKEN is not set; skipping failure notification"
exit 0
fi
SUMMARY="$(cat health-check-summary.txt 2>/dev/null || echo 'health check command failed')"
curl -X POST https://api.getmoshi.app/api/webhook \
-H "Content-Type: application/json" \
-d "{\"token\":\"${MOSHI_WEBHOOK_TOKEN}\",\"title\":\"Health Checks Failed\",\"message\":\"${GITHUB_REPOSITORY}: ${SUMMARY}\"}"