114 lines
3.7 KiB
Python
114 lines
3.7 KiB
Python
"""
|
|
阿龙电竞 - Celery工具函数
|
|
提供通用的Celery辅助函数,确保数据安全和操作稳定
|
|
【修复版】已解决装饰器导致Celery任务无法识别的问题
|
|
"""
|
|
|
|
import logging
|
|
from django.db import transaction
|
|
from datetime import datetime
|
|
from decimal import Decimal, InvalidOperation
|
|
import functools # 【核心修复】必须导入此模块
|
|
|
|
# 配置日志
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def safe_decimal_operation(value, default=Decimal('0.00')):
|
|
"""
|
|
安全处理Decimal操作,防止类型转换错误
|
|
:param value: 输入值
|
|
:param default: 默认值
|
|
:return: Decimal对象
|
|
"""
|
|
try:
|
|
if value is None:
|
|
return default
|
|
|
|
if isinstance(value, Decimal):
|
|
return value
|
|
|
|
if isinstance(value, (int, float)):
|
|
return Decimal(str(value))
|
|
|
|
if isinstance(value, str):
|
|
# 移除可能的空白字符和特殊字符
|
|
value = value.strip()
|
|
if not value:
|
|
return default
|
|
return Decimal(value)
|
|
|
|
# 其他类型尝试转换
|
|
return Decimal(str(value))
|
|
except (InvalidOperation, TypeError, ValueError) as e:
|
|
logger.warning(f"Decimal转换失败: {e}, 输入值: {value}, 类型: {type(value)}, 使用默认值: {default}")
|
|
return default
|
|
except Exception as e:
|
|
logger.error(f"Decimal转换发生未知错误: {e}, 输入值: {value}, 使用默认值: {default}")
|
|
return default
|
|
|
|
def log_task_execution(task_name, success=True, details=""):
|
|
"""
|
|
记录任务执行日志
|
|
:param task_name: 任务名称
|
|
:param success: 是否成功
|
|
:param details: 详细信息
|
|
"""
|
|
try:
|
|
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
status = "成功" if success else "失败"
|
|
|
|
log_message = f"[{timestamp}] {task_name} - {status}"
|
|
if details:
|
|
log_message += f" | {details}"
|
|
|
|
if success:
|
|
logger.info(log_message)
|
|
else:
|
|
logger.error(log_message)
|
|
|
|
return log_message
|
|
except Exception as e:
|
|
# 即使日志记录失败也不影响主流程
|
|
print(f"日志记录失败: {e}")
|
|
return f"日志记录失败: {e}"
|
|
|
|
def rollback_on_failure(operation_name):
|
|
"""
|
|
事务回滚装饰器(修复版)
|
|
:param operation_name: 操作名称
|
|
"""
|
|
def decorator(func):
|
|
@functools.wraps(func) # 【核心修复】保留原函数元数据,使Celery能正确识别任务
|
|
def wrapper(*args, **kwargs):
|
|
try:
|
|
with transaction.atomic():
|
|
return func(*args, **kwargs)
|
|
except Exception as e:
|
|
logger.error(f"{operation_name}事务执行失败: {str(e)}")
|
|
raise
|
|
return wrapper
|
|
return decorator
|
|
|
|
def retry_on_failure(max_retries=3, delay=60):
|
|
"""
|
|
重试装饰器(修复版,可用于Celery任务)
|
|
:param max_retries: 最大重试次数
|
|
:param delay: 重试延迟(秒)
|
|
"""
|
|
def decorator(func):
|
|
@functools.wraps(func) # 【核心修复】保留原函数元数据
|
|
def wrapper(*args, **kwargs):
|
|
retries = 0
|
|
while retries < max_retries:
|
|
try:
|
|
return func(*args, **kwargs)
|
|
except Exception as e:
|
|
retries += 1
|
|
if retries == max_retries:
|
|
logger.error(f"任务{func.__name__}重试{max_retries}次后失败: {str(e)}")
|
|
raise
|
|
logger.warning(f"任务{func.__name__}第{retries}次失败,{delay}秒后重试: {str(e)}")
|
|
import time
|
|
time.sleep(delay)
|
|
return wrapper
|
|
return decorator |