Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ ELASTICSEARCH_INDEX=btaa_geospatial_api
# Shared guard. Keep false locally/dev; prd deploy config defaults this true.
BACKUP_ENABLED=false
BACKUP_REQUIRED_DEST=prd
BACKUP_RETENTION_COUNT=3
BACKUP_RETENTION_COUNT=1
BACKUP_S3_BUCKET=
BACKUP_S3_PREFIX=btaa-geospatial-api
BACKUP_S3_REGION=us-east-2
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ KAMAL_REINDEX_REMOVE_LEGACY_INDEX ?= true
# If unset, the target falls back to APPLICATION_URL from Kamal env.
KAMAL_API_URL ?=
KAMAL_CACHE_TYPE ?= search
KAMAL_BACKUP_RETAIN_COUNT ?= 3
KAMAL_BACKUP_RETAIN_COUNT ?= 1
KAMAL_NETWORK_SELF_URL ?=
KAMAL_NETWORK_EXTERNAL_URLS ?= https://api.github.com https://raw.githubusercontent.com https://gin.btaa.org http://example.com
KAMAL_NETWORK_CONNECT_TIMEOUT ?= 5
Expand Down Expand Up @@ -1644,7 +1644,7 @@ kamal-backup-postgres: ## Run production-gated Postgres backup on Kamal
@kamal app exec -d $(KAMAL_DEST) --roles cron --reuse "bash -lc '/opt/venv/bin/python3 /app/scripts/backup_postgres_to_s3.py'"

# Manually run the production-gated Elasticsearch snapshot from the cron container.
# Usage: make kamal-backup-elasticsearch KAMAL_DEST=prd [KAMAL_BACKUP_RETAIN_COUNT=3]
# Usage: make kamal-backup-elasticsearch KAMAL_DEST=prd [KAMAL_BACKUP_RETAIN_COUNT=1]
kamal-backup-elasticsearch: ## Run production-gated Elasticsearch S3 snapshot on Kamal
@echo "Running Elasticsearch snapshot on Kamal cron container (KAMAL_DEST=$(KAMAL_DEST))..."
@if [ -z "$$KAMAL_SSH_USER" ] || [ -z "$$KAMAL_HOST" ]; then \
Expand Down
2 changes: 1 addition & 1 deletion backend/scripts/backup_postgres_to_s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
DEFAULT_DATABASE_NAME = "btaa_geospatial_api"
DEFAULT_PREFIX = "btaa-geospatial-api"
DEFAULT_REQUIRED_DEST = "prd"
DEFAULT_RETENTION_COUNT = 3
DEFAULT_RETENTION_COUNT = 1
LOCK_FILENAME = "postgres-backup.lock"


Expand Down
2 changes: 2 additions & 0 deletions backend/tests/scripts/test_backup_postgres_to_s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,15 @@ def test_build_config_supports_local_target(monkeypatch, tmp_path: Path):
monkeypatch.setenv("BACKUP_POSTGRES_TARGET", "local")
monkeypatch.setenv("BACKUP_LOCAL_DIR", str(tmp_path / "backups"))
monkeypatch.delenv("BACKUP_S3_BUCKET", raising=False)
monkeypatch.delenv("BACKUP_RETENTION_COUNT", raising=False)

config = backup._build_config()

assert config.target == "local"
assert config.bucket is None
assert config.local_dir == tmp_path / "backups"
assert config.work_dir == tmp_path / "backups" / ".tmp"
assert config.retention_count == 1


def test_prune_old_local_backups_keeps_newest_count(tmp_path: Path):
Expand Down
1 change: 1 addition & 0 deletions backend/tests/test_kamal_deploy_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ def test_prd_postgres_backup_uses_local_mounted_storage():
)
assert "ENV.fetch('BACKUP_POSTGRES_TARGET', 'local')" in config_text
assert "ENV.fetch('BACKUP_LOCAL_DIR', '/var/backups/btaa-geospatial-api')" in config_text
assert "ENV.fetch('BACKUP_RETENTION_COUNT', '1')" in config_text


def test_prd_memory_profile_protects_service_headroom():
Expand Down
2 changes: 1 addition & 1 deletion config/crontab
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ TZ=America/Chicago
30 5 * * * /opt/venv/bin/python3 /app/scripts/backup_postgres_to_s3.py >> /proc/1/fd/1 2>> /proc/1/fd/2

# Daily 5:45 AM: production-gated Elasticsearch snapshot to S3.
45 5 * * * /opt/venv/bin/python3 /app/scripts/backup_elasticsearch.py --scheduled --create --wait --retain-count ${BACKUP_RETENTION_COUNT:-3} >> /proc/1/fd/1 2>> /proc/1/fd/2
45 5 * * * /opt/venv/bin/python3 /app/scripts/backup_elasticsearch.py --scheduled --create --wait --retain-count ${BACKUP_RETENTION_COUNT:-1} >> /proc/1/fd/1 2>> /proc/1/fd/2

# Hourly: prune expired durable API response cache rows so the Postgres L2 cache
# stays bounded even if Redis is cold or search traffic is high.
Expand Down
2 changes: 1 addition & 1 deletion config/deploy.prd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ env:
BACKUP_REQUIRED_DEST: prd
BACKUP_POSTGRES_TARGET: "<%= ENV.fetch('BACKUP_POSTGRES_TARGET', 'local') %>"
BACKUP_LOCAL_DIR: "<%= ENV.fetch('BACKUP_LOCAL_DIR', '/var/backups/btaa-geospatial-api') %>"
BACKUP_RETENTION_COUNT: "<%= ENV.fetch('BACKUP_RETENTION_COUNT', '3') %>"
BACKUP_RETENTION_COUNT: "<%= ENV.fetch('BACKUP_RETENTION_COUNT', '1') %>"
BACKUP_S3_BUCKET: "<%= ENV.fetch('BACKUP_S3_BUCKET', '') %>"
BACKUP_S3_PREFIX: "<%= ENV.fetch('BACKUP_S3_PREFIX', 'btaa-geospatial-api') %>"
BACKUP_S3_REGION: "<%= ENV.fetch('BACKUP_S3_REGION', ENV.fetch('AWS_REGION', 'us-east-2')) %>"
Expand Down
2 changes: 1 addition & 1 deletion config/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ env:
BACKUP_REQUIRED_DEST: "prd"
BACKUP_POSTGRES_TARGET: "s3"
BACKUP_LOCAL_DIR: "<%= ENV.fetch('BACKUP_LOCAL_DIR', '/var/backups/btaa-geospatial-api') %>"
BACKUP_RETENTION_COUNT: "3"
BACKUP_RETENTION_COUNT: "1"
BACKUP_S3_BUCKET: "<%= ENV.fetch('BACKUP_S3_BUCKET', '') %>"
BACKUP_S3_PREFIX: "<%= ENV.fetch('BACKUP_S3_PREFIX', 'btaa-geospatial-api') %>"
BACKUP_S3_REGION: "<%= ENV.fetch('BACKUP_S3_REGION', ENV.fetch('AWS_REGION', 'us-east-2')) %>"
Expand Down
Loading