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 | ||