name: Ops cron (backup + IndexNow) # Scheduled operational jobs that don't belong in the app's own worker-tier # scheduler (notifications/scheduler.py, Track A chunk 5) because they're # infra/ops concerns rather than app-domain background work -- see the job # classification table in # docs/architecture/repo-topology-and-infrastructure.md ยง7. # # Both jobs SSH into the prod host and run inside the already-running compose # stack (docker compose exec), the same way deploy.sh already runs its own # post-deploy IndexNow ping -- no new network exposure, no separate dependency # install. Needs a runner registered with the `thermograph` label (Track B step # 5) and the same SSH secrets deploy.yml uses (SSH_HOST/SSH_USER/SSH_KEY/ # SSH_PORT) to reach the prod host. on: schedule: # 03:00 UTC daily -- a low-traffic window for both jobs. - cron: '0 3 * * *' workflow_dispatch: {} jobs: backup: name: pg_dump backup runs-on: [self-hosted, thermograph] steps: - name: Dump the prod database over SSH uses: appleboy/ssh-action@v1.2.0 with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_KEY }} port: ${{ secrets.SSH_PORT }} script: | set -euo pipefail cd /opt/thermograph backup_dir="$HOME/thermograph-backups" mkdir -p "$backup_dir" stamp="$(date -u +%Y%m%dT%H%M%SZ)" out="$backup_dir/thermograph-$stamp.dump" docker compose exec -T db pg_dump -U thermograph -d thermograph \ --format=custom > "$out" echo "wrote $out ($(du -h "$out" | cut -f1))" # The dumps are the disaster-recovery copy, not a versioned # archive -- keep the last 14 days and let the rest age out. find "$backup_dir" -name 'thermograph-*.dump' -mtime +14 -delete indexnow: name: IndexNow ping runs-on: [self-hosted, thermograph] steps: - name: Ping IndexNow if the URL set changed uses: appleboy/ssh-action@v1.2.0 with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_KEY }} port: ${{ secrets.SSH_PORT }} script: | set -euo pipefail cd /opt/thermograph set -a; . /etc/thermograph.env 2>/dev/null || true; set +a docker compose exec -T app python indexnow.py --if-changed \ "${THERMOGRAPH_BASE_URL:-https://thermograph.org}"