fix: clean stale partial database backups
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
All checks were successful
CD Pipeline / deploy (push) Successful in 1m8s
This commit is contained in:
@@ -20,6 +20,7 @@ DB_USER = os.environ.get("POSTGRES_USER", "momo")
|
||||
DB_NAME = os.environ.get("POSTGRES_DB", "momo_analytics")
|
||||
# 保留天數
|
||||
RETENTION_DAYS = int(os.environ.get("BACKUP_RETENTION_DAYS", "7"))
|
||||
PARTIAL_BACKUP_MIN_AGE_MINUTES = int(os.environ.get("PARTIAL_BACKUP_MIN_AGE_MINUTES", "60"))
|
||||
|
||||
|
||||
def _ensure_backup_dir():
|
||||
@@ -35,6 +36,30 @@ def _remove_partial_backup(filepath: str):
|
||||
logger.warning(f"[Backup] 移除不完整備份檔失敗 {filepath}: {exc}")
|
||||
|
||||
|
||||
def cleanup_partial_backups(min_age_minutes: int = PARTIAL_BACKUP_MIN_AGE_MINUTES) -> int:
|
||||
"""清除失敗後殘留的 0 byte 備份檔,避免監控與人工查檔誤判。"""
|
||||
_ensure_backup_dir()
|
||||
try:
|
||||
min_age_minutes = max(0, int(min_age_minutes))
|
||||
except (TypeError, ValueError):
|
||||
min_age_minutes = 60
|
||||
cutoff = datetime.now() - timedelta(minutes=min_age_minutes)
|
||||
deleted = 0
|
||||
for filepath in glob.glob(os.path.join(BACKUP_DIR, "momo_analytics_*.sql.gz")):
|
||||
try:
|
||||
if os.path.getsize(filepath) != 0:
|
||||
continue
|
||||
mtime = datetime.fromtimestamp(os.path.getmtime(filepath))
|
||||
if mtime > cutoff:
|
||||
continue
|
||||
os.remove(filepath)
|
||||
deleted += 1
|
||||
logger.info(f"[Backup] 已清除 0 byte 不完整備份: {os.path.basename(filepath)}")
|
||||
except Exception as exc:
|
||||
logger.warning(f"[Backup] 清除不完整備份失敗 {filepath}: {exc}")
|
||||
return deleted
|
||||
|
||||
|
||||
def _ensure_pg_dump_available() -> str:
|
||||
pg_dump_path = shutil.which("pg_dump")
|
||||
if pg_dump_path:
|
||||
@@ -175,10 +200,10 @@ def run_backup() -> dict:
|
||||
|
||||
|
||||
def cleanup_old_backups() -> int:
|
||||
"""刪除超過保留期限的備份檔,回傳刪除數量"""
|
||||
"""刪除不完整與超過保留期限的備份檔,回傳刪除數量。"""
|
||||
_ensure_backup_dir()
|
||||
cutoff = datetime.now() - timedelta(days=RETENTION_DAYS)
|
||||
deleted = 0
|
||||
deleted = cleanup_partial_backups()
|
||||
for f in glob.glob(os.path.join(BACKUP_DIR, "momo_analytics_*.sql.gz")):
|
||||
try:
|
||||
mtime = datetime.fromtimestamp(os.path.getmtime(f))
|
||||
|
||||
Reference in New Issue
Block a user