极简工作流引擎设计基于状态机的轻量级编排内核实现——不依赖重型框架用500行代码搭建可控的业务流程引擎一、为什么创业团队不需要Camunda、Activiti这些重型引擎创业团队在业务流程编排上面临一个典型困境审批流、数据管道、任务分发等场景需要流程编排能力但引入Camunda或Activiti这样的BPM引擎意味着要接受其完整的技术栈——流程定义语言BPMN XML、独立的流程引擎服务、任务队列管理、历史数据存储。这些引擎的设计目标是企业级复杂流程管理承载的是跨部门、多层级的审批流场景。创业团队的流程编排需求远没有这么复杂3-5步的任务链、简单的条件分支、偶尔的并行节点。引入重型引擎的代价是部署复杂度增加、调试困难、团队成员需要学习BPMN规范。本文设计一个基于状态机的轻量级工作流引擎用约500行代码覆盖创业团队80%的编排需求剩下20%通过扩展而非换引擎来解决。二、状态机驱动的工作流模型从BPMN抽象到极简状态图重型BPMN引擎的核心抽象是流程定义执行实例。本文的极简引擎同样采用定义与实例分离的设计但将BPMN的丰富节点类型UserTask、ServiceTask、Gateway等简化为三种状态节点、条件转换、并行分组。stateDiagram-v2 [*] -- Submitted: 创建工单 Submitted -- Reviewing: 自动流转 Reviewing -- Approved: 审核通过 Reviewing -- Rejected: 审核拒绝 Approved -- Executing: 执行分配 Executing -- Completed: 任务完成 Executing -- Failed: 执行异常 Failed -- RetryQueue: 自动重试 RetryQueue -- Executing: 重试触发 Rejected -- [*]: 流程终止 Completed -- [*]: 流程结束上图展示了一个典型审批-执行流程的状态机模型。与BPMN相比省略了泳道、子流程、事件监听等概念保留核心的状态流转逻辑。每个状态节点对应一个明确的业务动作每个转换对应一个条件判断。核心数据模型设计from dataclasses import dataclass, field from datetime import datetime from enum import Enum from typing import Any, Callable, Optional class NodeKind(Enum): 节点类型三种抽象覆盖大部分业务场景 START start # 起始节点流程入口 STATE state # 状态节点执行业务动作 END end # 终止节点流程结束标记 class TransitionKind(Enum): 转换类型条件驱动与自动驱动 CONDITION condition # 条件转换需要判断表达式 AUTO auto # 自动转换无条件自动流转 PARALLEL parallel # 并行转换同时进入多个状态 dataclass class WorkflowNode: 工作流节点定义包含执行动作与节点元信息 id: str # 节点唯一标识 kind: NodeKind # 节点类型 label: str # 业务语义标签如审核中 action: Optional[Callable] None # 节点执行动作进入此状态时触发 timeout_seconds: int 0 # 超时阈值0表示不限制 retry_limit: int 0 # 重试上限0表示不重试 dataclass class WorkflowTransition: 工作流转换定义描述状态间的流转条件 id: str # 转换唯一标识 from_node: str # 源节点ID to_node: str # 目标节点ID kind: TransitionKind # 转换类型 condition: Optional[str] None # 条件表达式Python布尔表达式字符串 priority: int 0 # 优先级同一源节点的多条转换按优先级排序 dataclass class WorkflowDef: 工作流定义节点与转换的集合构成完整状态机 id: str # 工作流定义ID name: str # 工作流名称 nodes: dict[str, WorkflowNode] field(default_factorydict) transitions: list[WorkflowTransition] field(default_factorylist) version: str 1.0.0 # 定义版本便于灰度升级 dataclass class WorkflowInstance: 工作流执行实例运行时的状态追踪与持久化 instance_id: str # 实例唯一ID definition_id: str # 关联的工作流定义ID current_node: str # 当前所处节点ID status: str running # 实例状态running/completed/failed/paused context: dict[str, Any] field(default_factorydict) # 业务上下文数据 history: list[dict] field(default_factorylist) # 状态流转历史 created_at: datetime field(default_factorydatetime.now) updated_at: datetime field(default_factorydatetime.now) retry_count: dict[str, int] field(default_factorydict) # 各节点重试计数三、引擎内核的实现状态流转、条件评估与异常恢复状态流转引擎核心代码import uuid import logging from datetime import datetime logger logging.getLogger(workflow-engine) class WorkflowEngine: 极简工作流引擎基于状态机的流转驱动内核 def __init__(self): self.definitions: dict[str, WorkflowDef] {} self.instances: dict[str, WorkflowInstance] {} # 节点动作注册表允许外部注册自定义动作避免硬编码 self.action_registry: dict[str, Callable] {} def register_definition(self, defn: WorkflowDef) - None: 注册工作流定义校验完整性后存入定义表 # 校验1起始节点必须存在且唯一 start_nodes [ n for n in defn.nodes.values() if n.kind NodeKind.START ] if len(start_nodes) ! 1: raise ValueError( f工作流 {defn.id} 必须有且仅有1个起始节点当前有 {len(start_nodes)} 个 ) # 校验2每个非终止节点必须有至少一条出边转换 for node in defn.nodes.values(): if node.kind ! NodeKind.END: out_edges [ t for t in defn.transitions if t.from_node node.id ] if not out_edges: raise ValueError( f节点 {node.id} 无出边转换流程将在此处卡死 ) # 校验3转换的源和目标节点必须在定义中存在 for t in defn.transitions: if t.from_node not in defn.nodes: raise ValueError(f转换 {t.id} 的源节点 {t.from_node} 不存在) if t.to_node not in defn.nodes: raise ValueError(f转换 {t.id} 的目标节点 {t.to_node} 不存在) self.definitions[defn.id] defn logger.info(f注册工作流定义: {defn.id} v{defn.version}) def create_instance( self, definition_id: str, context: dict[str, Any] None ) - WorkflowInstance: 创建工作流实例从起始节点开始执行 defn self.definitions.get(definition_id) if not defn: raise ValueError(f工作流定义 {definition_id} 未注册) start_node next( n for n in defn.nodes.values() if n.kind NodeKind.START ) instance WorkflowInstance( instance_idstr(uuid.uuid4()), definition_iddefinition_id, current_nodestart_node.id, contextcontext or {}, ) self.instances[instance.instance_id] instance # 起始节点创建后立即尝试自动流转 self._try_auto_transition(defn, instance) return instance def advance( self, instance_id: str, trigger_data: dict[str, Any] None, ) - WorkflowInstance: 推进工作流实例评估条件并执行状态转换 instance self.instances.get(instance_id) if not instance: raise ValueError(f实例 {instance_id} 不存在) if instance.status ! running: raise ValueError( f实例 {instance_id} 状态为 {instance.status}无法推进 ) defn self.definitions[instance.definition_id] # 合并触发数据到上下文外部事件数据注入流程上下文 if trigger_data: instance.context.update(trigger_data) # 执行当前节点的动作先执行业务逻辑再评估转换 current_node defn.nodes[instance.current_node] self._execute_node_action(current_node, instance) # 评估所有出边转换按优先级排序匹配第一条满足条件的 out_transitions sorted( [t for t in defn.transitions if t.from_node instance.current_node], keylambda t: t.priority, ) matched_transition None for t in out_transitions: if t.kind TransitionKind.AUTO: matched_transition t break elif t.kind TransitionKind.CONDITION: if self._evaluate_condition(t.condition, instance.context): matched_transition t break elif t.kind TransitionKind.PARALLEL: # 并行转换暂不处理完整并行逻辑标记为需扩展 matched_transition t break if not matched_transition: # 无匹配转换实例暂停等待外部触发 instance.status paused instance.updated_at datetime.now() logger.info( f实例 {instance_id} 在节点 {instance.current_node} 无匹配转换暂停等待 ) return instance # 执行转换更新当前节点记录流转历史 target_node defn.nodes[matched_transition.to_node] old_node instance.current_node instance.current_node matched_transition.to_node instance.history.append({ transition_id: matched_transition.id, from: old_node, to: matched_transition.to_node, timestamp: datetime.now().isoformat(), trigger_data: trigger_data, }) # 到达终止节点标记实例完成 if target_node.kind NodeKind.END: instance.status completed logger.info(f实例 {instance_id} 流程完成终止节点: {target_node.id}) # 到达异常节点且可重试更新重试计数 elif target_node.retry_limit 0: retry_key target_node.id instance.retry_count.setdefault(retry_key, 0) if instance.retry_count[retry_key] target_node.retry_limit: instance.retry_count[retry_key] 1 logger.info( f实例 {instance_id} 在节点 {target_node.id} 重试 f{instance.retry_count[retry_key]}/{target_node.retry_limit} ) instance.updated_at datetime.now() return instance def _evaluate_condition( self, condition_expr: str, context: dict[str, Any] ) - bool: 评估条件表达式使用受限的Python eval仅允许布尔运算 # 安全限制仅允许context变量参与运算禁止函数调用和导入 allowed_names {k: v for k, v in context.items()} try: result eval(condition_expr, {__builtins__: {}}, allowed_names) return bool(result) except Exception as e: logger.warning(f条件表达式评估失败: {condition_expr}, 错误: {e}) return False def _execute_node_action( self, node: WorkflowNode, instance: WorkflowInstance ) - None: 执行节点动作调用注册的业务函数 if not node.action: # 查找动作注册表中的替代动作 action self.action_registry.get(node.id) if not action: return # 无动作的节点仅作为状态标记 action_func node.action or self.action_registry.get(node.id) try: action_func(instance.context) except Exception as e: logger.error(f节点 {node.id} 动作执行失败: {e}) # 动作失败不终止流程标记错误信息到上下文后续节点可据此决策 instance.context[_last_action_error] str(e) instance.context[_last_action_failed_node] node.id def _try_auto_transition( self, defn: WorkflowDef, instance: WorkflowInstance ) - None: 尝试自动流转起始节点和自动转换节点的即时推进 out_transitions [ t for t in defn.transitions if t.from_node instance.current_node and t.kind TransitionKind.AUTO ] if out_transitions: # 有自动转换直接推进到目标节点 target defn.nodes[out_transitions[0].to_node] instance.current_node out_transitions[0].to_node instance.history.append({ transition_id: out_transitions[0].id, from: start, to: out_transitions[0].to_node, timestamp: datetime.now().isoformat(), trigger_data: None, })构建一个审批-执行流程的完整示例# 定义审批-执行工作流提交→审核→执行→完成 approval_workflow WorkflowDef( idapproval-execution, name审批执行流程, ) # 注册节点每个节点对应一个业务状态 approval_workflow.nodes { start: WorkflowNode(idstart, kindNodeKind.START, label提交), reviewing: WorkflowNode( idreviewing, kindNodeKind.STATE, label审核中, actionlambda ctx: print(f审核员 {ctx.get(reviewer)} 开始审核), timeout_seconds3600, # 审核超时1小时 ), approved: WorkflowNode( idapproved, kindNodeKind.STATE, label已通过, actionlambda ctx: ctx.update({approved_at: datetime.now().isoformat()}), ), executing: WorkflowNode( idexecuting, kindNodeKind.STATE, label执行中, retry_limit3, # 执行失败最多重试3次 ), completed: WorkflowNode(idcompleted, kindNodeKind.END, label已完成), rejected: WorkflowNode(idrejected, kindNodeKind.END, label已拒绝), failed: WorkflowNode(idfailed, kindNodeKind.END, label执行失败), } # 注册转换条件驱动的状态流转逻辑 approval_workflow.transitions [ WorkflowTransition(idt1, from_nodestart, to_nodereviewing, kindTransitionKind.AUTO), WorkflowTransition(idt2, from_nodereviewing, to_nodeapproved, kindTransitionKind.CONDITION, conditiondecision approve, priority1), WorkflowTransition(idt3, from_nodereviewing, to_noderejected, kindTransitionKind.CONDITION, conditiondecision reject, priority2), WorkflowTransition(idt4, from_nodeapproved, to_nodeexecuting, kindTransitionKind.AUTO), WorkflowTransition(idt5, from_nodeexecuting, to_nodecompleted, kindTransitionKind.CONDITION, conditionresult success), WorkflowTransition(idt6, from_nodeexecuting, to_nodefailed, kindTransitionKind.CONDITION, conditionresult error and retry_count 3), ] # 使用引擎执行流程 engine WorkflowEngine() engine.register_definition(approval_workflow) # 创建实例并推进 instance engine.create_instance(approval-execution, {task: 数据导出}) # 审核员决策注入decision字段触发条件转换 engine.advance(instance.instance_id, {decision: approve, reviewer: admin01}) # 执行结果注入result字段完成流程 engine.advance(instance.instance_id, {result: success})四、极简引擎的边界能力上限与扩展策略当前引擎的能力边界graph TD subgraph 已覆盖能力 C1[线性流程: A→B→C→D] C2[条件分支: A→B或A→C] C3[简单重试: 失败节点有限次重试] C4[上下文传递: 节点间共享业务数据] C5[历史追踪: 完整流转日志记录] end subgraph 未覆盖能力 U1[完整并行: 多节点同时执行与汇聚] U2[子流程嵌套: 流程内嵌套流程] U3[定时触发: 基于时间的节点激活] U4[外部事件监听: 异步回调驱动流转] U5[动态增删节点: 运行时修改流程定义] end扩展策略而非替换策略当业务需求超出当前引擎能力时不建议直接切换到重型BPM引擎。而是按以下策略扩展并行节点扩展引入ParallelNode类型和JoinNode类型。ParallelNode同时触发多个子节点JoinNode等待所有子节点完成后汇聚。实现复杂度增加约200行代码但无需引入外部引擎。定时触发扩展为WorkflowInstance增加scheduled_transitions字段由外部调度器如APScheduler按时间触发advance调用。引擎本身不内置调度逻辑保持内核极简。外部事件监听扩展定义EventBridge接口外部系统通过HTTP回调将事件数据注入实例上下文并调用advance。引擎不关心事件来源只关心上下文数据。适用与禁用场景适用3-5步的审批流、数据管道编排、任务分发与结果收集、简单条件分支流程、创业团队内部工具流程。禁用跨部门多层级审批需要子流程和权限控制、复杂并行汇聚逻辑需要完整BPMN并行网关、需要可视化流程设计器的场景、流程定义需要非技术人员编辑的场景、流程实例量超过10万/月的超高并发场景。五、总结极简工作流引擎的设计哲学是用最少的抽象覆盖最多的实际需求。状态机模型提供核心流转能力三种节点类型和三种转换类型覆盖80%的创业场景编排需求。引擎内核约500行代码无需外部数据库依赖实例可持久化到Redis或文件系统部署运维成本为零。当业务需求超出引擎能力边界时优先考虑扩展而非替换并行节点、定时触发、事件监听等能力可通过增量代码实现而非引入完整的BPMN引擎栈。创业团队的核心约束是人力有限每个新增基础设施组件都意味着一份运维负担。极简引擎的目标不是功能完备而是ROI最优最少代码覆盖最多场景最少依赖产生最少故障。
极简工作流引擎设计:基于状态机的轻量级编排内核实现——不依赖重型框架,用500行代码搭建可控的业务流程引擎
发布时间:2026/7/7 0:55:39
极简工作流引擎设计基于状态机的轻量级编排内核实现——不依赖重型框架用500行代码搭建可控的业务流程引擎一、为什么创业团队不需要Camunda、Activiti这些重型引擎创业团队在业务流程编排上面临一个典型困境审批流、数据管道、任务分发等场景需要流程编排能力但引入Camunda或Activiti这样的BPM引擎意味着要接受其完整的技术栈——流程定义语言BPMN XML、独立的流程引擎服务、任务队列管理、历史数据存储。这些引擎的设计目标是企业级复杂流程管理承载的是跨部门、多层级的审批流场景。创业团队的流程编排需求远没有这么复杂3-5步的任务链、简单的条件分支、偶尔的并行节点。引入重型引擎的代价是部署复杂度增加、调试困难、团队成员需要学习BPMN规范。本文设计一个基于状态机的轻量级工作流引擎用约500行代码覆盖创业团队80%的编排需求剩下20%通过扩展而非换引擎来解决。二、状态机驱动的工作流模型从BPMN抽象到极简状态图重型BPMN引擎的核心抽象是流程定义执行实例。本文的极简引擎同样采用定义与实例分离的设计但将BPMN的丰富节点类型UserTask、ServiceTask、Gateway等简化为三种状态节点、条件转换、并行分组。stateDiagram-v2 [*] -- Submitted: 创建工单 Submitted -- Reviewing: 自动流转 Reviewing -- Approved: 审核通过 Reviewing -- Rejected: 审核拒绝 Approved -- Executing: 执行分配 Executing -- Completed: 任务完成 Executing -- Failed: 执行异常 Failed -- RetryQueue: 自动重试 RetryQueue -- Executing: 重试触发 Rejected -- [*]: 流程终止 Completed -- [*]: 流程结束上图展示了一个典型审批-执行流程的状态机模型。与BPMN相比省略了泳道、子流程、事件监听等概念保留核心的状态流转逻辑。每个状态节点对应一个明确的业务动作每个转换对应一个条件判断。核心数据模型设计from dataclasses import dataclass, field from datetime import datetime from enum import Enum from typing import Any, Callable, Optional class NodeKind(Enum): 节点类型三种抽象覆盖大部分业务场景 START start # 起始节点流程入口 STATE state # 状态节点执行业务动作 END end # 终止节点流程结束标记 class TransitionKind(Enum): 转换类型条件驱动与自动驱动 CONDITION condition # 条件转换需要判断表达式 AUTO auto # 自动转换无条件自动流转 PARALLEL parallel # 并行转换同时进入多个状态 dataclass class WorkflowNode: 工作流节点定义包含执行动作与节点元信息 id: str # 节点唯一标识 kind: NodeKind # 节点类型 label: str # 业务语义标签如审核中 action: Optional[Callable] None # 节点执行动作进入此状态时触发 timeout_seconds: int 0 # 超时阈值0表示不限制 retry_limit: int 0 # 重试上限0表示不重试 dataclass class WorkflowTransition: 工作流转换定义描述状态间的流转条件 id: str # 转换唯一标识 from_node: str # 源节点ID to_node: str # 目标节点ID kind: TransitionKind # 转换类型 condition: Optional[str] None # 条件表达式Python布尔表达式字符串 priority: int 0 # 优先级同一源节点的多条转换按优先级排序 dataclass class WorkflowDef: 工作流定义节点与转换的集合构成完整状态机 id: str # 工作流定义ID name: str # 工作流名称 nodes: dict[str, WorkflowNode] field(default_factorydict) transitions: list[WorkflowTransition] field(default_factorylist) version: str 1.0.0 # 定义版本便于灰度升级 dataclass class WorkflowInstance: 工作流执行实例运行时的状态追踪与持久化 instance_id: str # 实例唯一ID definition_id: str # 关联的工作流定义ID current_node: str # 当前所处节点ID status: str running # 实例状态running/completed/failed/paused context: dict[str, Any] field(default_factorydict) # 业务上下文数据 history: list[dict] field(default_factorylist) # 状态流转历史 created_at: datetime field(default_factorydatetime.now) updated_at: datetime field(default_factorydatetime.now) retry_count: dict[str, int] field(default_factorydict) # 各节点重试计数三、引擎内核的实现状态流转、条件评估与异常恢复状态流转引擎核心代码import uuid import logging from datetime import datetime logger logging.getLogger(workflow-engine) class WorkflowEngine: 极简工作流引擎基于状态机的流转驱动内核 def __init__(self): self.definitions: dict[str, WorkflowDef] {} self.instances: dict[str, WorkflowInstance] {} # 节点动作注册表允许外部注册自定义动作避免硬编码 self.action_registry: dict[str, Callable] {} def register_definition(self, defn: WorkflowDef) - None: 注册工作流定义校验完整性后存入定义表 # 校验1起始节点必须存在且唯一 start_nodes [ n for n in defn.nodes.values() if n.kind NodeKind.START ] if len(start_nodes) ! 1: raise ValueError( f工作流 {defn.id} 必须有且仅有1个起始节点当前有 {len(start_nodes)} 个 ) # 校验2每个非终止节点必须有至少一条出边转换 for node in defn.nodes.values(): if node.kind ! NodeKind.END: out_edges [ t for t in defn.transitions if t.from_node node.id ] if not out_edges: raise ValueError( f节点 {node.id} 无出边转换流程将在此处卡死 ) # 校验3转换的源和目标节点必须在定义中存在 for t in defn.transitions: if t.from_node not in defn.nodes: raise ValueError(f转换 {t.id} 的源节点 {t.from_node} 不存在) if t.to_node not in defn.nodes: raise ValueError(f转换 {t.id} 的目标节点 {t.to_node} 不存在) self.definitions[defn.id] defn logger.info(f注册工作流定义: {defn.id} v{defn.version}) def create_instance( self, definition_id: str, context: dict[str, Any] None ) - WorkflowInstance: 创建工作流实例从起始节点开始执行 defn self.definitions.get(definition_id) if not defn: raise ValueError(f工作流定义 {definition_id} 未注册) start_node next( n for n in defn.nodes.values() if n.kind NodeKind.START ) instance WorkflowInstance( instance_idstr(uuid.uuid4()), definition_iddefinition_id, current_nodestart_node.id, contextcontext or {}, ) self.instances[instance.instance_id] instance # 起始节点创建后立即尝试自动流转 self._try_auto_transition(defn, instance) return instance def advance( self, instance_id: str, trigger_data: dict[str, Any] None, ) - WorkflowInstance: 推进工作流实例评估条件并执行状态转换 instance self.instances.get(instance_id) if not instance: raise ValueError(f实例 {instance_id} 不存在) if instance.status ! running: raise ValueError( f实例 {instance_id} 状态为 {instance.status}无法推进 ) defn self.definitions[instance.definition_id] # 合并触发数据到上下文外部事件数据注入流程上下文 if trigger_data: instance.context.update(trigger_data) # 执行当前节点的动作先执行业务逻辑再评估转换 current_node defn.nodes[instance.current_node] self._execute_node_action(current_node, instance) # 评估所有出边转换按优先级排序匹配第一条满足条件的 out_transitions sorted( [t for t in defn.transitions if t.from_node instance.current_node], keylambda t: t.priority, ) matched_transition None for t in out_transitions: if t.kind TransitionKind.AUTO: matched_transition t break elif t.kind TransitionKind.CONDITION: if self._evaluate_condition(t.condition, instance.context): matched_transition t break elif t.kind TransitionKind.PARALLEL: # 并行转换暂不处理完整并行逻辑标记为需扩展 matched_transition t break if not matched_transition: # 无匹配转换实例暂停等待外部触发 instance.status paused instance.updated_at datetime.now() logger.info( f实例 {instance_id} 在节点 {instance.current_node} 无匹配转换暂停等待 ) return instance # 执行转换更新当前节点记录流转历史 target_node defn.nodes[matched_transition.to_node] old_node instance.current_node instance.current_node matched_transition.to_node instance.history.append({ transition_id: matched_transition.id, from: old_node, to: matched_transition.to_node, timestamp: datetime.now().isoformat(), trigger_data: trigger_data, }) # 到达终止节点标记实例完成 if target_node.kind NodeKind.END: instance.status completed logger.info(f实例 {instance_id} 流程完成终止节点: {target_node.id}) # 到达异常节点且可重试更新重试计数 elif target_node.retry_limit 0: retry_key target_node.id instance.retry_count.setdefault(retry_key, 0) if instance.retry_count[retry_key] target_node.retry_limit: instance.retry_count[retry_key] 1 logger.info( f实例 {instance_id} 在节点 {target_node.id} 重试 f{instance.retry_count[retry_key]}/{target_node.retry_limit} ) instance.updated_at datetime.now() return instance def _evaluate_condition( self, condition_expr: str, context: dict[str, Any] ) - bool: 评估条件表达式使用受限的Python eval仅允许布尔运算 # 安全限制仅允许context变量参与运算禁止函数调用和导入 allowed_names {k: v for k, v in context.items()} try: result eval(condition_expr, {__builtins__: {}}, allowed_names) return bool(result) except Exception as e: logger.warning(f条件表达式评估失败: {condition_expr}, 错误: {e}) return False def _execute_node_action( self, node: WorkflowNode, instance: WorkflowInstance ) - None: 执行节点动作调用注册的业务函数 if not node.action: # 查找动作注册表中的替代动作 action self.action_registry.get(node.id) if not action: return # 无动作的节点仅作为状态标记 action_func node.action or self.action_registry.get(node.id) try: action_func(instance.context) except Exception as e: logger.error(f节点 {node.id} 动作执行失败: {e}) # 动作失败不终止流程标记错误信息到上下文后续节点可据此决策 instance.context[_last_action_error] str(e) instance.context[_last_action_failed_node] node.id def _try_auto_transition( self, defn: WorkflowDef, instance: WorkflowInstance ) - None: 尝试自动流转起始节点和自动转换节点的即时推进 out_transitions [ t for t in defn.transitions if t.from_node instance.current_node and t.kind TransitionKind.AUTO ] if out_transitions: # 有自动转换直接推进到目标节点 target defn.nodes[out_transitions[0].to_node] instance.current_node out_transitions[0].to_node instance.history.append({ transition_id: out_transitions[0].id, from: start, to: out_transitions[0].to_node, timestamp: datetime.now().isoformat(), trigger_data: None, })构建一个审批-执行流程的完整示例# 定义审批-执行工作流提交→审核→执行→完成 approval_workflow WorkflowDef( idapproval-execution, name审批执行流程, ) # 注册节点每个节点对应一个业务状态 approval_workflow.nodes { start: WorkflowNode(idstart, kindNodeKind.START, label提交), reviewing: WorkflowNode( idreviewing, kindNodeKind.STATE, label审核中, actionlambda ctx: print(f审核员 {ctx.get(reviewer)} 开始审核), timeout_seconds3600, # 审核超时1小时 ), approved: WorkflowNode( idapproved, kindNodeKind.STATE, label已通过, actionlambda ctx: ctx.update({approved_at: datetime.now().isoformat()}), ), executing: WorkflowNode( idexecuting, kindNodeKind.STATE, label执行中, retry_limit3, # 执行失败最多重试3次 ), completed: WorkflowNode(idcompleted, kindNodeKind.END, label已完成), rejected: WorkflowNode(idrejected, kindNodeKind.END, label已拒绝), failed: WorkflowNode(idfailed, kindNodeKind.END, label执行失败), } # 注册转换条件驱动的状态流转逻辑 approval_workflow.transitions [ WorkflowTransition(idt1, from_nodestart, to_nodereviewing, kindTransitionKind.AUTO), WorkflowTransition(idt2, from_nodereviewing, to_nodeapproved, kindTransitionKind.CONDITION, conditiondecision approve, priority1), WorkflowTransition(idt3, from_nodereviewing, to_noderejected, kindTransitionKind.CONDITION, conditiondecision reject, priority2), WorkflowTransition(idt4, from_nodeapproved, to_nodeexecuting, kindTransitionKind.AUTO), WorkflowTransition(idt5, from_nodeexecuting, to_nodecompleted, kindTransitionKind.CONDITION, conditionresult success), WorkflowTransition(idt6, from_nodeexecuting, to_nodefailed, kindTransitionKind.CONDITION, conditionresult error and retry_count 3), ] # 使用引擎执行流程 engine WorkflowEngine() engine.register_definition(approval_workflow) # 创建实例并推进 instance engine.create_instance(approval-execution, {task: 数据导出}) # 审核员决策注入decision字段触发条件转换 engine.advance(instance.instance_id, {decision: approve, reviewer: admin01}) # 执行结果注入result字段完成流程 engine.advance(instance.instance_id, {result: success})四、极简引擎的边界能力上限与扩展策略当前引擎的能力边界graph TD subgraph 已覆盖能力 C1[线性流程: A→B→C→D] C2[条件分支: A→B或A→C] C3[简单重试: 失败节点有限次重试] C4[上下文传递: 节点间共享业务数据] C5[历史追踪: 完整流转日志记录] end subgraph 未覆盖能力 U1[完整并行: 多节点同时执行与汇聚] U2[子流程嵌套: 流程内嵌套流程] U3[定时触发: 基于时间的节点激活] U4[外部事件监听: 异步回调驱动流转] U5[动态增删节点: 运行时修改流程定义] end扩展策略而非替换策略当业务需求超出当前引擎能力时不建议直接切换到重型BPM引擎。而是按以下策略扩展并行节点扩展引入ParallelNode类型和JoinNode类型。ParallelNode同时触发多个子节点JoinNode等待所有子节点完成后汇聚。实现复杂度增加约200行代码但无需引入外部引擎。定时触发扩展为WorkflowInstance增加scheduled_transitions字段由外部调度器如APScheduler按时间触发advance调用。引擎本身不内置调度逻辑保持内核极简。外部事件监听扩展定义EventBridge接口外部系统通过HTTP回调将事件数据注入实例上下文并调用advance。引擎不关心事件来源只关心上下文数据。适用与禁用场景适用3-5步的审批流、数据管道编排、任务分发与结果收集、简单条件分支流程、创业团队内部工具流程。禁用跨部门多层级审批需要子流程和权限控制、复杂并行汇聚逻辑需要完整BPMN并行网关、需要可视化流程设计器的场景、流程定义需要非技术人员编辑的场景、流程实例量超过10万/月的超高并发场景。五、总结极简工作流引擎的设计哲学是用最少的抽象覆盖最多的实际需求。状态机模型提供核心流转能力三种节点类型和三种转换类型覆盖80%的创业场景编排需求。引擎内核约500行代码无需外部数据库依赖实例可持久化到Redis或文件系统部署运维成本为零。当业务需求超出引擎能力边界时优先考虑扩展而非替换并行节点、定时触发、事件监听等能力可通过增量代码实现而非引入完整的BPMN引擎栈。创业团队的核心约束是人力有限每个新增基础设施组件都意味着一份运维负担。极简引擎的目标不是功能完备而是ROI最优最少代码覆盖最多场景最少依赖产生最少故障。