Files
dpb/backend/app/utils/backup_job.py
T

63 lines
2.1 KiB
Python
Raw Normal View History

"""每日 02:00 数据库备份 job —— 包装 backend/scripts/pg_backup.sh。
独立脚本可手动/CI 直跑;系统调度经此包装,保证与脚本同一份备份逻辑与轮转策略。
Windows 下须显式定位 Git BashPATH 里的 bash 可能是 WSL shimmount/PATH 均不匹配),
脚本路径统一转 MSYS /d/... 格式传给子进程。
"""
import asyncio
import logging
import shutil
from pathlib import Path
logger = logging.getLogger(__name__)
# backend/app/utils/backup_job.py → parents[2] = backend/
_SCRIPT = Path(__file__).resolve().parents[2] / "scripts" / "pg_backup.sh"
_GIT_BASH_CANDIDATES = (
Path(r"C:\Program Files\Git\bin\bash.exe"),
Path(r"C:\Program Files\Git\usr\bin\bash.exe"),
)
def _find_git_bash() -> str | None:
for cand in _GIT_BASH_CANDIDATES:
if cand.exists():
return str(cand)
return shutil.which("bash")
def _msys_path(p: Path) -> str:
"""D:/dpb/... → /d/dpb/...Git Bash 挂载约定)。"""
s = p.as_posix()
if len(s) >= 2 and s[1] == ":":
return f"/{s[0].lower()}{s[2:]}"
return s
async def run_daily_backup() -> bool:
"""每日备份:调用 pg_backup.sh(独立脚本,pg_dump 自定义格式 + N 天轮转)。"""
script = _SCRIPT
if not script.exists():
alt = Path.cwd() / "scripts" / "pg_backup.sh"
script = alt if alt.exists() else script
if not script.exists():
logger.error(f"备份脚本不存在: {script}")
return False
git_bash = _find_git_bash()
if not git_bash:
logger.error("未找到 Git BashC:/Program Files/Git/bin/bash.exe")
return False
proc = await asyncio.create_subprocess_exec(
git_bash, _msys_path(script),
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
stdout, stderr = await proc.communicate()
if proc.returncode == 0:
logger.info(f"每日备份完成: {stdout.decode().strip()}")
return True
logger.error(f"每日备份失败(rc={proc.returncode}): {stderr.decode()[:500]}")
return False