娣诲姞RSS鏁版嵁澶勭悊鍣ㄥ拰浠诲姟璋冨害鍔熻兘锛屾洿鏂伴厤缃拰鏃ュ織鏂囦欢
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user