refactor(workflow): enforce typed query boundary

This commit is contained in:
jxxghp
2026-08-28 01:16:08 +08:00
parent 2f41780893
commit b4f8736541
35 changed files with 733 additions and 223 deletions
+48 -34
View File
@@ -14,7 +14,11 @@ from typing import Any, Callable, List, Optional, Tuple
from pydantic import BaseModel
from app.application.chain.data import get_chain_workflow_port
from app.application.workflow import get_workflow_manager
from app.application.workflow import (
WorkflowSnapshot,
get_configured_workflow_query,
get_workflow_manager,
)
from app.chain import ChainBase
from app.runtime.events import Event, eventmanager
from app.runtime.execution import OwnedThreadPoolExecutor
@@ -27,9 +31,6 @@ ARTIFACT_FIELDS = {"torrents", "medias", "fileitems", "downloads", "sites", "sub
DEFAULT_WORKFLOW_MAX_WORKERS = 4
WORKFLOW_EXECUTOR_STOP_TIMEOUT_SECONDS = 10.0
CIRCULAR_REFERENCE_PLACEHOLDER = "[Circular]"
Workflow = Any
def _serialize_workflow_key(key: Any) -> Any:
"""将映射键转换为 JSON 安全值。"""
if key is None or isinstance(key, (str, int, float, bool)):
@@ -118,7 +119,11 @@ class WorkflowExecutor:
工作流执行器
"""
def __init__(self, workflow: Workflow, step_callback: Callable = None):
def __init__(
self,
workflow: WorkflowSnapshot,
step_callback: Callable = None,
):
"""
初始化工作流执行器
:param workflow: 工作流对象
@@ -132,8 +137,13 @@ class WorkflowExecutor:
if step_callback
else False
)
self.actions = {action['id']: Action(**action) for action in workflow.actions}
self.flows = [ActionFlow(**flow) for flow in workflow.flows]
self.actions: dict[str, Action] = {}
for action_data in workflow.actions:
action = Action(**dict(action_data))
if not action.id:
raise ValueError("工作流动作缺少 ID")
self.actions[action.id] = action
self.flows = [ActionFlow(**dict(flow)) for flow in workflow.flows]
execution_config = getattr(workflow, "execution_config", None) or {}
execution_state = getattr(workflow, "execution_state", None) or {}
self.execution_config = (
@@ -652,7 +662,8 @@ class WorkflowExecutor:
self.flow_satisfied.add(flow_key)
if not source_success and self.node_states.get(source_id) == "failed":
self.flow_failed.add(flow_key)
self.evaluate_target_state(flow.target)
if flow.target:
self.evaluate_target_state(flow.target)
def evaluate_target_state(self, target_id: str) -> None:
"""
@@ -1277,10 +1288,29 @@ class WorkflowChain(ChainBase):
"""
workflowoper = get_chain_workflow_port()
def save_step(action: Action, context: ActionContext, execution_state: dict, completed: bool):
"""
保存上下文到数据库
"""
# 重置工作流
if from_begin:
workflowoper.reset(workflow_id)
# 查询工作流数据
workflow = get_configured_workflow_query().get_sync(workflow_id)
if not workflow:
logger.warn(f"工作流 {workflow_id} 不存在")
return False, "工作流不存在"
if not workflow.actions:
logger.warn(f"工作流 {workflow.name} 无动作")
return False, "工作流无动作"
if not workflow.flows:
logger.warn(f"工作流 {workflow.name} 无流程")
return False, "工作流无流程"
def save_step(
action: Action,
context: ActionContext,
execution_state: dict,
completed: bool,
) -> None:
"""保存动作上下文和结构化执行状态。"""
get_chain_workflow_port().step(
workflow_id,
action_id=action.id if completed else "",
@@ -1305,22 +1335,6 @@ class WorkflowChain(ChainBase):
},
)
# 重置工作流
if from_begin:
workflowoper.reset(workflow_id)
# 查询工作流数据
workflow = workflowoper.get(workflow_id)
if not workflow:
logger.warn(f"工作流 {workflow_id} 不存在")
return False, "工作流不存在"
if not workflow.actions:
logger.warn(f"工作流 {workflow.name} 无动作")
return False, "工作流无动作"
if not workflow.flows:
logger.warn(f"工作流 {workflow.name} 无流程")
return False, "工作流无流程"
logger.info(f"开始执行工作流 {workflow.name},共 {len(workflow.actions)} 个动作 ...")
if progress_callback:
progress_callback(
@@ -1355,22 +1369,22 @@ class WorkflowChain(ChainBase):
return True, ""
@staticmethod
def get_workflows() -> List[Workflow]:
def get_workflows() -> List[WorkflowSnapshot]:
"""
获取工作流列表
"""
return get_chain_workflow_port().list_enabled()
return get_configured_workflow_query().list_enabled()
@staticmethod
def get_timer_workflows() -> List[Workflow]:
def get_timer_workflows() -> List[WorkflowSnapshot]:
"""
获取定时触发的工作流列表
"""
return get_chain_workflow_port().get_timer_triggered_workflows()
return get_configured_workflow_query().list_timer_enabled()
@staticmethod
def get_event_workflows() -> List[Workflow]:
def get_event_workflows() -> List[WorkflowSnapshot]:
"""
获取事件触发的工作流列表
"""
return get_chain_workflow_port().get_event_triggered_workflows()
return get_configured_workflow_query().list_event_enabled()