#!/usr/bin/env bash # ShopDB backup WATCHER - the resident half of the in-app backup utility. # # WHY this exists: the api container cannot run docker, so when an operator # clicks "Back up now" the api only drops a sentinel file (.backup-requested) # on the shared backups volume. This watcher is the thing that actuates that # request: it polls for the sentinel and runs the one-shot backup.sh, which # ships a restic snapshot to the backup-store container and clears the sentinel # on success. That turns the UI button into a real, self-serve backup without # giving the api container any docker or host privileges. # # ASCII only, no emojis - matches the repo style gate. set -uo pipefail BACKUPS_ROOT="${SHOPDB_BACKUPS_ROOT:-/backups}" SENTINEL="${BACKUPS_ROOT}/.backup-requested" INTERVAL="${BACKUP_POLL_SECONDS:-10}" log() { echo "[backup-watch] $*"; } mkdir -p "${BACKUPS_ROOT}" log "watcher up; polling ${SENTINEL} every ${INTERVAL}s" while true; do if [ -f "${SENTINEL}" ]; then log "backup requested - running one-shot" if /opt/backup/backup.sh; then log "backup completed" else # backup.sh only clears the sentinel on success, so a failed run # would otherwise loop forever. Clear it here and wait for the next # explicit request rather than hammering a broken backup. log "backup FAILED - clearing request, awaiting next" rm -f "${SENTINEL}" 2>/dev/null || true fi fi sleep "${INTERVAL}" done