89 lines
3.0 KiB
Python
89 lines
3.0 KiB
Python
import asyncio
|
||
import functools
|
||
from typing import Callable, Any, TypeVar, Coroutine
|
||
from wechat_auto.utils.logger import logger
|
||
from wechat_auto.config import settings
|
||
|
||
T = TypeVar('T')
|
||
|
||
|
||
def async_retry(
|
||
max_retries: int = None,
|
||
base_delay: float = None,
|
||
exponential: bool = True,
|
||
exceptions: tuple = (Exception,)
|
||
):
|
||
max_retries = max_retries or settings.max_retries
|
||
base_delay = base_delay or settings.retry_base_delay
|
||
|
||
def decorator(func: Callable[..., Coroutine[Any, Any, T]]):
|
||
@functools.wraps(func)
|
||
async def wrapper(*args, **kwargs) -> T:
|
||
last_exception = None
|
||
|
||
for attempt in range(max_retries):
|
||
try:
|
||
return await func(*args, **kwargs)
|
||
except exceptions as e:
|
||
last_exception = e
|
||
if attempt < max_retries - 1:
|
||
if exponential:
|
||
delay = base_delay * (2 ** attempt)
|
||
else:
|
||
delay = base_delay
|
||
logger.warning(
|
||
f"{func.__name__} 失败,{attempt + 1}/{max_retries},"
|
||
f"{delay:.1f}秒后重试: {e}"
|
||
)
|
||
await asyncio.sleep(delay)
|
||
else:
|
||
logger.error(
|
||
f"{func.__name__} 失败,已达到最大重试次数 {max_retries}: {e}"
|
||
)
|
||
|
||
raise last_exception
|
||
|
||
return wrapper
|
||
return decorator
|
||
|
||
|
||
def sync_retry(
|
||
max_retries: int = None,
|
||
base_delay: float = None,
|
||
exponential: bool = True,
|
||
exceptions: tuple = (Exception,)
|
||
):
|
||
max_retries = max_retries or settings.max_retries
|
||
base_delay = base_delay or settings.retry_base_delay
|
||
|
||
def decorator(func: Callable[..., T]):
|
||
@functools.wraps(func)
|
||
def wrapper(*args, **kwargs) -> T:
|
||
last_exception = None
|
||
|
||
for attempt in range(max_retries):
|
||
try:
|
||
return func(*args, **kwargs)
|
||
except exceptions as e:
|
||
last_exception = e
|
||
if attempt < max_retries - 1:
|
||
if exponential:
|
||
delay = base_delay * (2 ** attempt)
|
||
else:
|
||
delay = base_delay
|
||
logger.warning(
|
||
f"{func.__name__} 失败,{attempt + 1}/{max_retries},"
|
||
f"{delay:.1f}秒后重试: {e}"
|
||
)
|
||
import time
|
||
time.sleep(delay)
|
||
else:
|
||
logger.error(
|
||
f"{func.__name__} 失败,已达到最大重试次数 {max_retries}: {e}"
|
||
)
|
||
|
||
raise last_exception
|
||
|
||
return wrapper
|
||
return decorator
|