Relevance — daily 3-day check-in #95
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: Relevance — daily 3-day check-in | |
| # Asks each event's owner once a day whether their 3-day-old report is still | |
| # relevant (push + queues the in-app modal). Same App Service constraint as | |
| # cluster-daily.yml: the student tier has no Always On, so we can't rely on | |
| # the in-process PeriodicTimer. This workflow guarantees one trigger per day. | |
| # | |
| # Re-uses the existing CLUSTERING_ADMIN_TOKEN secret. Both admin endpoints | |
| # (clustering + relevance) validate against the same server-side Admin:Token | |
| # config key, so a single token covers both. | |
| on: | |
| schedule: | |
| # 07:00 UTC = 10:00 Israel summer / 09:00 winter. Picked so the push | |
| # lands at a reasonable local time, not in the middle of the night. | |
| - cron: "0 7 * * *" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| notify: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Wake & run relevance check | |
| env: | |
| API_BASE: https://app-groundshare-api.azurewebsites.net | |
| ADMIN_TOKEN: ${{ secrets.CLUSTERING_ADMIN_TOKEN }} | |
| POLL_TIMEOUT: "180" | |
| POLL_INTERVAL: "10" | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${ADMIN_TOKEN}" ]; then | |
| echo "::error::CLUSTERING_ADMIN_TOKEN secret is not set." | |
| exit 1 | |
| fi | |
| json_field() { python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('$1') or '')"; } | |
| # 1. Wake the App Service (student tier sleeps on idle). | |
| echo "Pinging relevance diagnostics to warm the App Service..." | |
| for attempt in 1 2 3; do | |
| if curl -fsS --max-time 60 "${API_BASE}/api/relevance/diagnostics" >/tmp/diag.json; then | |
| cat /tmp/diag.json; echo | |
| break | |
| fi | |
| echo "Attempt ${attempt} failed, retrying..." | |
| sleep 15 | |
| done | |
| before=$(json_field lastRunUtc </tmp/diag.json) | |
| echo "lastRunUtc before run: '${before}'" | |
| # 2. Kick off the relevance run. Fire-and-forget: returns 202 immediately. | |
| echo "Triggering /run-now..." | |
| http_code=$(curl -sS -o /tmp/run.json -w "%{http_code}" \ | |
| --max-time 60 \ | |
| -X POST \ | |
| -H "X-Admin-Token: ${ADMIN_TOKEN}" \ | |
| "${API_BASE}/api/relevance/run-now") | |
| echo "HTTP ${http_code}" | |
| cat /tmp/run.json; echo | |
| # 202 Accepted is the success path; tolerate 200 during the deploy window. | |
| if [ "${http_code}" != "202" ] && [ "${http_code}" != "200" ]; then | |
| echo "::error::Relevance run-now trigger failed with HTTP ${http_code}" | |
| exit 1 | |
| fi | |
| # 3. Poll diagnostics until lastRunUtc advances past 'before'. | |
| echo "Polling for completion (timeout ${POLL_TIMEOUT}s)..." | |
| deadline=$(( $(date +%s) + POLL_TIMEOUT )) | |
| while :; do | |
| if curl -fsS --max-time 30 "${API_BASE}/api/relevance/diagnostics" >/tmp/diag.json; then | |
| after=$(json_field lastRunUtc </tmp/diag.json) | |
| if [ -n "${after}" ] && [ "${after}" != "${before}" ]; then | |
| echo "Relevance run complete. lastRunUtc now: '${after}'" | |
| cat /tmp/diag.json; echo | |
| exit 0 | |
| fi | |
| echo " still running (lastRunUtc='${after}')..." | |
| else | |
| echo " diagnostics ping failed, will retry..." | |
| fi | |
| if [ "$(date +%s)" -ge "${deadline}" ]; then | |
| echo "::error::Relevance run did not complete within ${POLL_TIMEOUT}s" | |
| cat /tmp/diag.json 2>/dev/null || true | |
| exit 1 | |
| fi | |
| sleep "${POLL_INTERVAL}" | |
| done |