fix: 优化 MySQL 重试机制,增加可重试错误类型并改进日志记录

This commit is contained in:
晓丰 2025-07-15 21:08:35 +08:00
parent 6c49ef042e
commit 0e7804451b

40
DB.py
View File

@ -92,34 +92,44 @@ video_author = Table(
) )
def mysql_retry(max_retries: int = 3, base_delay: float = 2.0): def mysql_retry(max_retries: int = 3, base_delay: float = 1.0):
""" RETRIABLE_ERRORS = {2013, 1213, 2006}
装饰器捕获断线异常InterfaceError OperationalError: 2013后尝试重连指数回退重试
"""
def decorator(fn): def decorator(fn):
@functools.wraps(fn) @functools.wraps(fn)
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
for attempt in range(1, max_retries + 1): for attempt in range(1, max_retries + 1):
try: try:
# 确保连接仍存活,失败自动 reconnect
self.conn.ping(reconnect=True) self.conn.ping(reconnect=True)
return fn(self, *args, **kwargs) return fn(self, *args, **kwargs)
except (pymysql.InterfaceError, pymysql.OperationalError) as e:
if isinstance(e, pymysql.OperationalError) and e.args[0] != 2013: except pymysql.OperationalError as e:
raise # 只处理 2013其他 OperationalError 抛出 errno = e.args[0]
wait = base_delay * (2 ** (attempt - 1)) if errno not in RETRIABLE_ERRORS:
logger.warning(f"[MySQL][{fn.__name__}] 第{attempt}次重试(断开连接:{e}),等待 {wait:.1f}s 后重连…")
time.sleep(wait)
self._reconnect_mysql()
if attempt == max_retries:
logger.error("[MySQL] 重试多次仍失败,抛出异常")
raise raise
reason = {
2013: "连接断开",
1213: "死锁冲突",
2006: "连接失效",
}.get(errno, f"MySQL错误{errno}")
wait = base_delay * (2 ** (attempt - 1))
logger.warning(f"[MySQL][{fn.__name__}] 第{attempt}次重试({errno} {reason}{e},等待 {wait:.1f}s...")
# 仅对断连类错误尝试重连
if errno in {2013, 2006}:
self._reconnect_mysql()
time.sleep(wait)
logger.error(f"[MySQL] 函数 `{fn.__name__}` 重试 {max_retries} 次仍失败,最终异常:{e}")
raise
return wrapper return wrapper
return decorator return decorator
def redis_retry(max_retries: int = 3): def redis_retry(max_retries: int = 3):
""" """
装饰器工厂指定最大重试次数 装饰器工厂指定最大重试次数