S37: Spaces lifecycle + cross-region sync
- SHA
9a4c42bc8ccf1b3acceb1678cdf6082745486c4e- Parents
-
5cdd4d4 - Tree
95e30e2
9a4c42b
9a4c42bc8ccf1b3acceb1678cdf6082745486c4e5cdd4d4
95e30e2| Status | File | + | - |
|---|---|---|---|
| A |
deploy/spaces/lifecycle.json
|
23 | 0 |
| A |
deploy/spaces/sync-cross-region.sh
|
36 | 0 |
deploy/spaces/lifecycle.jsonadded@@ -0,0 +1,23 @@ | ||
| 1 | +{ | |
| 2 | + "_comment": "DigitalOcean Spaces lifecycle (S3-compatible). Apply with `s3cmd setlifecycle lifecycle.json s3://shithub-backups`. Two prefixes: WAL segments (cheaper to keep, archive sooner) and daily logical dumps (kept longer, primary recovery path).", | |
| 3 | + "Rules": [ | |
| 4 | + { | |
| 5 | + "ID": "wal-30day-retention", | |
| 6 | + "Status": "Enabled", | |
| 7 | + "Filter": {"Prefix": ""}, | |
| 8 | + "Expiration": {"Days": 30} | |
| 9 | + }, | |
| 10 | + { | |
| 11 | + "ID": "daily-90day-retention", | |
| 12 | + "Status": "Enabled", | |
| 13 | + "Filter": {"Prefix": "daily/"}, | |
| 14 | + "Expiration": {"Days": 90} | |
| 15 | + }, | |
| 16 | + { | |
| 17 | + "ID": "abort-stale-multipart", | |
| 18 | + "Status": "Enabled", | |
| 19 | + "Filter": {"Prefix": ""}, | |
| 20 | + "AbortIncompleteMultipartUpload": {"DaysAfterInitiation": 2} | |
| 21 | + } | |
| 22 | + ] | |
| 23 | +} | |
deploy/spaces/sync-cross-region.shadded@@ -0,0 +1,36 @@ | ||
| 1 | +#!/usr/bin/env bash | |
| 2 | +# SPDX-License-Identifier: AGPL-3.0-or-later | |
| 3 | +# | |
| 4 | +# Cross-region copy from the primary Spaces bucket (NYC3) to the | |
| 5 | +# DR bucket (SFO3). Run on a schedule from the backup host (the one | |
| 6 | +# that already has rclone configured), NOT from the app server — | |
| 7 | +# we don't want a runaway sync to evict app pages from cache. | |
| 8 | +# | |
| 9 | +# rclone copy is incremental (size + mtime), so this is cheap on | |
| 10 | +# steady-state and only moves new objects. | |
| 11 | + | |
| 12 | +set -euo pipefail | |
| 13 | + | |
| 14 | +PRIMARY="${SHITHUB_BACKUP_BUCKET:-spaces-prod:shithub-backups}" | |
| 15 | +DR="${SHITHUB_DR_BUCKET:-spaces-dr:shithub-backups-dr}" | |
| 16 | +WAL_PRIMARY="${SHITHUB_WAL_BUCKET:-spaces-prod:shithub-wal}" | |
| 17 | +WAL_DR="${SHITHUB_WAL_DR_BUCKET:-spaces-dr:shithub-wal-dr}" | |
| 18 | + | |
| 19 | +LOG="/var/log/shithub/spaces-sync.log" | |
| 20 | +mkdir -p "$(dirname "$LOG")" | |
| 21 | + | |
| 22 | +ts() { date -u +%Y-%m-%dT%H:%M:%SZ; } | |
| 23 | + | |
| 24 | +{ | |
| 25 | + echo "[$(ts)] sync start" | |
| 26 | + | |
| 27 | + rclone --config /root/.config/rclone/rclone.conf \ | |
| 28 | + copy --transfers 8 --checkers 16 --fast-list \ | |
| 29 | + "$PRIMARY" "$DR" | |
| 30 | + | |
| 31 | + rclone --config /root/.config/rclone/rclone.conf \ | |
| 32 | + copy --transfers 8 --checkers 16 --fast-list \ | |
| 33 | + "$WAL_PRIMARY" "$WAL_DR" | |
| 34 | + | |
| 35 | + echo "[$(ts)] sync end" | |
| 36 | +} >> "$LOG" 2>&1 | |