娣诲姞RSS鏁版嵁澶勭悊鍣ㄥ拰浠诲姟璋冨害鍔熻兘锛屾洿鏂伴厤缃拰鏃ュ織鏂囦欢

This commit is contained in:
z66
2025-10-29 10:39:13 +08:00
parent c5f6e8288d
commit fc18fa74c3
27 changed files with 3559 additions and 361 deletions
+81 -41
View File
@@ -246,50 +246,90 @@ class TaskScheduler:
except Exception:
pass
def _execute_task_logic(self, task: Dict[str, Any]) -> None:
"""执行任务的具体逻辑(动态导入模块)"""
start_time = time.time()
task_id = task['task_id']
module_path = task['module_path']
task_log = log.bind(task_id=task_id, module=module_path)
def _execute_task_logic(self, task):
"""
执行任务逻辑的核心方法
支持类方法、静态方法和实例方法的调用
"""
module_path = task.get('module_path')
if not module_path:
raise ValueError("任务缺少 module_path 配置")
# 解析模块路径和类名
try:
path_parts = module_path.split('.')
if len(path_parts) < 2:
raise ValueError(f"无效的模块路径: {module_path}")
module_name = '.'.join(path_parts[:-1])
class_name = path_parts[-1]
method_name = 'main' # 默认方法名
except Exception as e:
raise ValueError(f"解析模块路径失败: {str(e)}")
# 动态导入模块
try:
import importlib
module = importlib.import_module(module_name)
except ImportError as e:
raise ImportError(f"无法导入模块 {module_name}: {str(e)}")
# 获取类和方法
if not hasattr(module, class_name):
raise AttributeError(f"模块 {module_name} 中未找到类 {class_name}")
cls = getattr(module, class_name)
# 检查是否存在指定方法
if not hasattr(cls, method_name):
raise AttributeError(f"{class_name} 中未找到方法 {method_name}")
method = getattr(cls, method_name)
# 根据方法类型决定如何调用
import inspect
callable_entry = None
# 判断是否为静态方法或类方法
if isinstance(method, staticmethod):
# 静态方法可以直接调用
callable_entry = method
elif isinstance(method, classmethod):
# 类方法需要传入类作为第一个参数
callable_entry = method
else:
# 实例方法或普通函数
try:
# 尝试检查方法签名
sig = inspect.signature(method)
params = list(sig.parameters.values())
# 如果第一个参数是self且没有默认值,则认为是实例方法
if params and params[0].name == 'self' and params[0].default == inspect.Parameter.empty:
# 创建实例并获取绑定方法
instance = cls()
callable_entry = getattr(instance, method_name)
else:
# 可能是普通函数或者是带有默认self参数的方法
callable_entry = method
except Exception:
# 如果检查签名失败,默认尝试创建实例
try:
instance = cls()
callable_entry = getattr(instance, method_name)
except Exception:
# 如果创建实例也失败,则直接调用方法(适用于不需要self的特殊情况)
callable_entry = method
# 执行任务
if not callable(callable_entry):
raise TypeError(f"{module_path}.{method_name} 不是可调用对象")
try:
# 解析可调用入口(支持模块/类/函数路径)
# 若路径最终为类,先实例化再调 main;否则直接调用
target_obj = None
parts = module_path.split('.') if isinstance(module_path, str) else []
resolved = None
try:
# 尝试导入尽可能深的模块
for i in range(len(parts), 0, -1):
mod = importlib.import_module('.'.join(parts[:i]))
attr_chain = parts[i:]
obj = mod
for attr in attr_chain:
obj = getattr(obj, attr)
resolved = obj
break
except Exception:
resolved = None
if isinstance(resolved, type):
try:
target_obj = resolved() # 触发 __init__ 日志
if hasattr(target_obj, 'main') and callable(getattr(target_obj, 'main')):
task_log.debug("开始执行实例的 main()")
getattr(target_obj, 'main')()
else:
raise AttributeError(f"{resolved.__name__} 未提供可调用的 main()")
except Exception as e:
raise
else:
callable_entry = self._resolve_callable(module_path)
task_log.debug("开始执行任务入口函数")
callable_entry()
task_log.info(f"任务执行完成,耗时: {time.time() - start_time:.2f}")
# 执行任务逻辑
callable_entry()
except Exception as e:
task_log.error("任务逻辑执行失败", exc_info=True)
self.logger.error(f"任务逻辑执行失败: {str(e)}")
raise
def _calculate_next_run_time(self, cron_expr: str, time_zone: str = 'Asia/Shanghai') -> datetime: