#!/usr/bin/env python # -*- coding: utf-8 -*- """ 任务上下文模块 提供任务执行过程中的上下文管理 """ import json import logging from typing import Dict, List, Any, Optional from datetime import datetime from utils.logger import get_logger # 获取日志记录器 logger = get_logger("services.execution.task_context") class TaskContext: """ 任务上下文类 管理任务执行过程中的数据、变量和状态 """ def __init__( self, task_record_id: str, task_def_id: str, input_params: Dict[str, Any], variables: Dict[str, Any] = None, token: str = None ): """ 初始化任务上下文 Args: task_record_id: 任务记录ID task_def_id: 任务定义ID input_params: 任务输入参数 variables: 任务变量,默认为空字典 """ self.task_record_id = task_record_id self.task_def_id = task_def_id self.input_params = input_params or {} self.variables = variables or {} self.variable_sources = {} # 记录每个变量的来源块 self.execution_path = [] # 执行路径 self.outputs = {} # 任务输出 self.block_outputs = {} # 各块的输出结果 self.error = None # 错误信息 self.start_time = datetime.now() # 开始时间 self.is_canceled = False # 是否被取消 self.current_block_id = None # 当前正在执行的块ID self.current_block_name = None # 当前正在执行的块名称 self.skip_to_component_id = None # 需要跳转到的块ID self._variables_need_sync = False # 变量是否需要同步到数据库 self.token = token # 任务令牌 def set_current_block(self, block_id: str, block_name: str): """ 设置当前正在执行的块 Args: block_id: 块ID block_name: 块名称 """ self.current_block_id = block_id self.current_block_name = block_name def get_variable(self, name: str, default: Any = None) -> Any: """ 获取变量值 Args: name: 变量名 default: 默认值,如果变量不存在则返回此值 Returns: Any: 变量值 """ # 检查是否是任务输入参数 if name.startswith("taskInputs."): param_name = name[len("taskInputs."):] # 查找参数信息 if isinstance(self.input_params, list): # 若input_params是列表格式,需要查找参数信息并从defaultValue字段获取值 for param in self.input_params: if param.get('name') == param_name: return param.get('defaultValue', default) return default else: # 旧的处理方式,直接从字典中获取值 return self.input_params.get(param_name, default) # 检查是否是块输出 if name.startswith("outputs."): output_path = name[len("outputs."):].split(".") current = self.block_outputs for key in output_path: if key in current: current = current[key] else: return default return current # 普通变量 return self.variables.get(name, default) def set_variable(self, name: str, value: Any) -> None: """ 设置变量值 Args: name: 变量名 value: 变量值 """ # 不允许修改任务输入参数 if name.startswith("taskInputs."): logger.warning(f"尝试修改任务输入参数 {name},操作被忽略") return # 设置变量 self.variables[name] = value # 标记需要同步变量 self._variables_need_sync = True # 记录变量来源 if self.current_block_id and self.current_block_name: self.variable_sources[name] = { "block_id": self.current_block_id, "block_name": self.current_block_name, "timestamp": datetime.now().isoformat() } def get_variable_source(self, name: str) -> Optional[Dict[str, str]]: """ 获取变量的来源信息 Args: name: 变量名 Returns: Optional[Dict[str, str]]: 变量来源信息,如果不存在则返回None """ return self.variable_sources.get(name) def get_block_variables(self, block_id: str = None, block_name: str = None) -> Dict[str, Any]: """ 获取由指定块设置的所有变量 Args: block_id: 块ID block_name: 块名称 Returns: Dict[str, Any]: 变量字典 """ result = {} # 如果既不指定block_id也不指定block_name,返回空字典 if not block_id and not block_name: return result # 遍历所有变量来源 for var_name, source in self.variable_sources.items(): # 按块ID匹配 if block_id and source.get("block_id") == block_id: result[var_name] = self.variables.get(var_name) # 按块名称匹配 elif block_name and source.get("block_name") == block_name: result[var_name] = self.variables.get(var_name) return result def set_block_output(self, block_id: str, output: Dict[str, Any]) -> None: """ 设置块输出 Args: block_id: 块ID output: 输出值 """ self.block_outputs[block_id] = output def get_block_output(self, block_id: str) -> Any: """ 获取块输出 Args: block_id: 块ID Returns: Any: 块的输出值,如果不存在则返回None """ return self.block_outputs.get(block_id) def add_execution_path(self, block_id: str) -> None: """ 添加执行路径 Args: block_id: 块ID """ self.execution_path.append({ "blockId": block_id, "timestamp": datetime.now().isoformat() }) def set_error(self, error: str, block_id: str = None) -> None: """ 设置错误信息 Args: error: 错误信息 block_id: 发生错误的块ID """ self.error = { "message": error, "blockId": block_id, "timestamp": datetime.now().isoformat() } def set_output(self, key: str, value: Any) -> None: """ 设置任务输出 Args: key: 输出键名 value: 输出值 """ self.outputs[key] = value def mark_canceled(self) -> None: """标记任务为已取消状态""" self.is_canceled = True def is_task_canceled(self) -> bool: """ 检查任务是否被取消 Returns: bool: 是否被取消 """ return self.is_canceled def get_execution_time(self) -> int: """ 获取任务已执行时间(毫秒) Returns: int: 执行时间(毫秒) """ delta = datetime.now() - self.start_time return int(delta.total_seconds() * 1000) def set_skip_to(self, component_id: str) -> None: """ 设置任务需要跳转到的块ID Args: component_id: 目标块ID """ self.skip_to_component_id = component_id logger.info(f"设置任务跳转至组件: {component_id}") def get_skip_to(self) -> Optional[str]: """ 获取任务需要跳转到的块ID Returns: Optional[str]: 如果设置了跳转目标则返回目标块ID,否则返回None """ return self.skip_to_component_id def clear_skip_to(self) -> None: """ 清除跳转标记 """ self.skip_to_component_id = None def to_dict(self) -> Dict[str, Any]: """ 将上下文转换为字典 Returns: Dict[str, Any]: 上下文字典 """ return { "taskRecordId": self.task_record_id, "taskDefId": self.task_def_id, "inputParams": self.input_params, "variables": self.variables, "variableSources": self.variable_sources, "executionPath": self.execution_path, "outputs": self.outputs, "blockOutputs": self.block_outputs, "error": self.error, "startTime": self.start_time.isoformat(), "executionTime": self.get_execution_time(), "isCanceled": self.is_canceled, "skipToComponentId": self.skip_to_component_id } def need_sync_variables(self) -> bool: """ 检查变量是否需要同步到数据库 Returns: bool: 是否需要同步 """ return self._variables_need_sync def mark_variables_synced(self) -> None: """ 标记变量已同步到数据库 """ self._variables_need_sync = False