add banbanmini backend
This commit is contained in:
105
talkingq-url/scripts/backup_db.py
Normal file
105
talkingq-url/scripts/backup_db.py
Normal file
@@ -0,0 +1,105 @@
|
||||
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}")
|
||||
Reference in New Issue
Block a user