好,选 B 非常关键 👍 这一步会把你的 bpm-engine 从“自定义工作流内核”正式推进到“工业级 BPM 引擎”。

下面我给你一份 「BPMN 2.0 → 你当前 Engine 的 Runtime 映射设计」,目标是:

不推翻你现有 Token / Scheduler / External Task / Saga 设计 只在 Definition Layer 做 BPMN 适配

这是可分阶段落地、不会把你项目拖进泥潭的方案。


🧠 一、总体设计思想(非常重要)

核心原则(你一定要坚持)

✅ 1. BPMN 只是「定义语言」,不是执行模型

✅ 2. Token 模型保持不变

✅ 3. 只支持 BPMN 的「可执行子集」

第一阶段绝不追求全量 BPMN(那是地狱)


🧩 二、分层架构(Definition → Runtime)

BPMN XML
   │
   ▼
BpmnParser
   │
   ▼
BpmnModel (AST)
   │
   ▼
ProcessCompiler
   │
   ▼
Engine ProcessDefinition
   │
   ▼
Token Runtime (你已有的)

👉 关键点: ProcessCompiler 是整个设计的“心脏”


📐 三、你需要支持的 BPMN 最小可执行集(MVP)

第一阶段(90% 实际业务)

BPMN 元素 是否必须 说明
startEvent ✅ 单一 start
endEvent ✅ 正常结束
sequenceFlow ✅ 带条件
serviceTask ✅ External Task
userTask ✅ Human Task
exclusiveGateway ✅ if / else
parallelGateway ✅ fork / join
boundaryTimerEvent ⭕ 可第二阶段

⚠️ 暂时不支持:


🧬 四、BPMN → Engine Core Model 映射

1️⃣ BPMN Node → Engine Node

你可以引入一个统一的中间表示:

pub struct CompiledNode {
    pub node_id: NodeId,
    pub node_type: NodeType,
    pub outgoing: Vec<SequenceFlow>,
}

NodeType 映射

pub enum NodeType {
    Start,
    End,

    ServiceTask {
        task_type: String,
    },

    UserTask {
        form_key: Option<String>,
    },

    ExclusiveGateway,
    ParallelGateway,
}

2️⃣ Sequence Flow(核心)

pub struct SequenceFlow {
    pub target: NodeId,
    pub condition: Option<Expression>,
}

Expression 可以先支持:

后续你可以换成 CEL / rhai / evalexpr。


🔁 五、Token 行为映射(重点)

🟢 StartEvent

create Token
→ move to outgoing[0]

🔵 ServiceTask(External Task)

Token arrives
→ create ExternalTask
→ Token WAITING
→ Worker complete
→ Token resumes
→ evaluate outgoing

对应你现在已有的 External Task 机制,完全匹配。


🟡 UserTask

Token arrives
→ create HumanTask
→ WAITING
→ user completes
→ Token resumes

HumanTask 和 ExternalTask 在 Engine 里可以共用一个抽象(Execution)。


🔀 ExclusiveGateway(XOR)

Token arrives
→ evaluate outgoing in order
→ pick first condition == true
→ move Token

⚠️ BPMN 规范:


🔱 ParallelGateway(Fork)

Token arrives
→ for each outgoing
    spawn new Token
→ original token consumed

🔱 ParallelGateway(Join)

Token arrives
→ wait until all incoming tokens arrived
→ merge → single Token
→ move forward

你已经有并行 Token 设计,这一步是 映射而非重写。


🧠 六、Join 的关键:Execution Scope

BPMN 的 join 本质是:

同一流程实例、同一 Gateway、同一执行作用域

推荐设计(非常重要)

struct JoinKey {
    process_instance_id,
    gateway_id,
}

👉 你已有 Token Join 的话,只需要挂一个 gateway_id


🧩 七、ProcessCompiler(最关键的模块)

输入

输出

pub struct ProcessDefinition {
    pub id: ProcessId,
    pub nodes: HashMap<NodeId, CompiledNode>,
    pub start_node: NodeId,
}

Compiler 做 5 件事(缺一不可)

  1. 校验 BPMN 合法性
  2. 构建节点图
  3. 解析 condition expression
  4. 识别 gateway join / fork
  5. 生成 Engine 可执行结构

🧪 八、最小实现路径(别一次做太多)

Phase 1(2–3 周)

👉 目标:一个 BPMN 文件能跑


Phase 2(2–3 周)


Phase 3(可选)


📌 九、你的 repo 中我建议新增的目录

bpm-engine
├── bpmn/
│   ├── parser.rs
│   ├── model.rs
│   ├── compiler.rs
│   └── errors.rs
├── engine/
│   └── process_definition.rs

BPMN 永远不要污染 engine runtime 包


🏁 十、关键结论(请你记住)

BPMN 是 DSL,不是 Runtime

你现在这个引擎:

BPMN 只是:

让用户用标准方式“描述”你已经能执行的东西


下一步我可以继续(强烈建议)

你可以继续选一个:

直接回 B1 / B2 / B3 / B4 我继续陪你把这个引擎打到「专业级」 💪