diff --git a/.forgejo/workflows/ops-cron.yml b/.forgejo/workflows/ops-cron.yml new file mode 100644 index 0000000..21ab8f6 --- /dev/null +++ b/.forgejo/workflows/ops-cron.yml @@ -0,0 +1,64 @@ +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}"