Files
banban/talkingq-url/scripts/backup_db.py
2026-03-24 15:04:36 +08:00

106 lines
3.2 KiB
Python

import os
import sys
import asyncio
import aiomysql
import subprocess
import datetime
import gzip
import shutil
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent))
from config import settings
BACKUP_DIR = os.path.join(Path(__file__).parent.parent, "backups")
os.makedirs(BACKUP_DIR, exist_ok=True)
async def backup_database(name=None, compress=True):
"""备份MySQL数据库"""
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
if name:
backup_name = f"{name}_{timestamp}"
else:
backup_name = f"backup_{timestamp}"
output_file = os.path.join(BACKUP_DIR, f"{backup_name}.sql")
cmd = [
"mysqldump",
"-h", settings.db_host,
"-P", str(settings.db_port),
"-u", settings.db_user,
f"-p{settings.db_password}",
"--single-transaction",
"--routines",
"--triggers",
"--events",
settings.db_name
]
try:
print(f"开始备份数据库...")
with open(output_file, 'w') as f:
process = subprocess.Popen(
cmd,
stdout=f,
stderr=subprocess.PIPE
)
_, stderr = process.communicate()
if process.returncode != 0:
print(f"备份失败: {stderr.decode()}")
if os.path.exists(output_file):
os.remove(output_file)
return False
if compress:
compressed_file = f"{output_file}.gz"
print(f"压缩备份文件...")
with open(output_file, 'rb') as f_in:
with gzip.open(compressed_file, 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
os.remove(output_file) # 删除未压缩的SQL文件
output_file = compressed_file
file_size = os.path.getsize(output_file) / (1024 * 1024) # 转换为MB
print(f"备份完成: {output_file} ({file_size:.2f} MB)")
return output_file
except Exception as e:
print(f"备份过程中出错: {e}")
if os.path.exists(output_file):
os.remove(output_file)
return False
async def list_backups():
"""列出所有可用的备份文件"""
if not os.path.exists(BACKUP_DIR):
return []
backups = [f for f in os.listdir(BACKUP_DIR) if f.endswith('.sql') or f.endswith('.sql.gz')]
backups.sort(reverse=True) # 按文件名排序,最新的在前面
return backups
async def cleanup_old_backups(keep=10):
"""清理旧备份,仅保留指定数量的最新备份"""
backups = await list_backups()
if len(backups) <= keep:
print(f"当前共有 {len(backups)} 个备份,未超过保留数量 {keep},不需要清理")
return
to_delete = backups[keep:]
print(f"将删除 {len(to_delete)} 个旧备份,保留 {keep} 个最新备份")
for backup in to_delete:
try:
file_path = os.path.join(BACKUP_DIR, backup)
os.remove(file_path)
print(f"已删除: {backup}")
except Exception as e:
print(f"删除备份 {backup} 时出错: {e}")