26 KiB
Workflow Engine 技术产品文档
版本:v1.0 · 最后更新:2026-05-09
目录
1. 概述
1.1 定位
raisfast 内置工作流引擎,为 CMS 内容发布流程提供自动化编排能力。设计目标:
- 轻量:不依赖外部服务(无 Redis/MQ),数据全部存储在 SQLite 中
- 同步驱动:步骤推进由 API 调用触发,而非后台轮询(除 Delay 类型)
- 声明式定义:工作流以 JSON 定义步骤和转移关系,存储在
workflow_definitions表 - 可观测:每步执行生成
workflow_step_logs记录,含输入/输出/耗时
1.2 设计原则
| 原则 | 说明 |
|---|---|
| 极简核心 | 5 种步骤类型覆盖 90% 常见场景 |
| 单实例单步骤 | 任意时刻一个实例只处于一个当前步骤(Parallel 除外) |
| Context 传递 | 工作流上下文在步骤间自动传递和合并 |
| 幂等安全 | 定义创建时校验所有引用完整性 |
1.3 不做的事
- 不做分布式协调(无 leader election、分布式锁)
- 不做 DAG 拓扑(无复杂依赖图)
- 不做可视化编辑器后端(前端自行实现)
- 不做跨系统编排(无 HTTP callback、无 gRPC 调用)
2. 架构
┌─────────────────────────────────────────────────┐
│ HTTP API │
│ /admin/workflows CRUD │
│ /admin/workflows/{id}/start │
│ /admin/workflows/instances/{id}/execute │
│ /admin/workflows/instances/{id}/cancel │
│ /admin/workflows/instances/{id}/logs │
└────────────────────┬────────────────────────────┘
│
┌────────────────────▼────────────────────────────┐
│ WorkflowService │
│ ┌─────────────┐ ┌──────────────────────────┐ │
│ │ validate │ │ execute_step │ │
│ │ _steps │ │ ├─ Task/Await/Delay │ │
│ │ │ │ ├─ Branch (条件路由) │ │
│ │ resolve │ │ └─ Parallel (并行→汇合) │ │
│ │ _next_step │ │ │ │
│ └─────────────┘ └──────────────────────────┘ │
└────────────────────┬────────────────────────────┘
│
┌────────────────────▼────────────────────────────┐
│ Model 层 (sqlx) │
│ workflow_definitions │
│ workflow_instances │
│ workflow_step_logs │
└─────────────────────────────────────────────────┘
三层分离
| 层 | 文件 | 职责 |
|---|---|---|
| Handler | src/handlers/workflow.rs |
HTTP 请求解析、参数校验、响应封装 |
| Service | src/services/workflow.rs |
状态机逻辑、步骤解析、条件评估、并行调度 |
| Model | src/models/workflow.rs |
SQL 查询、数据结构映射 |
3. 数据模型
3.1 workflow_definitions — 工作流定义
| 字段 | 类型 | 说明 |
|---|---|---|
id |
INTEGER PK | 自增主键 |
document_id |
TEXT UNIQUE | UUID v7,对外暴露的 ID |
name |
TEXT | 工作流名称 |
description |
TEXT? | 描述 |
steps |
TEXT | JSON 数组,步骤定义(见 4.1) |
initial_step |
TEXT | 入口步骤 ID |
version |
INTEGER | 版本号(当前未使用,预留) |
enabled |
BOOLEAN | 是否启用,禁用时无法启动新实例 |
created_at |
TEXT | ISO 8601 |
updated_at |
TEXT | ISO 8601 |
3.2 workflow_instances — 工作流实例
| 字段 | 类型 | 说明 |
|---|---|---|
id |
INTEGER PK | 自增主键 |
document_id |
TEXT UNIQUE | UUID v7 |
definition_id |
INTEGER FK | 关联定义 |
status |
TEXT | running / completed / failed / cancelled |
current_step |
TEXT? | 当前步骤 ID(completed/failed/cancelled 时为 NULL) |
context |
TEXT | JSON,工作流上下文(跨步骤传递) |
triggered_by |
INTEGER? | 触发者 user.id |
started_at |
TEXT | 启动时间 |
completed_at |
TEXT? | 完成时间 |
updated_at |
TEXT | 最后更新 |
实例状态机:
start_workflow
│
▼
┌──────────┐
┌───────│ running │───────┐
│ └──────────┘ │
│ │ │ │
execute_step cancel fail_step │
│ │ │ │
▼ ▼ ▼ │
┌──────────┐ │ ┌─────────┐ │
│ running │ │ │ failed │ │
│(下一步) │ │ └─────────┘ │
└──────────┘ │ │
│ ▼ │
│ ┌───────────┐ │
│ │ cancelled │ │
│ └───────────┘ │
▼ │
┌───────────┐ │
│ completed │◄──────────────────┘
└───────────┘ (最后一步 next 为空)
3.3 workflow_step_logs — 步骤执行日志
| 字段 | 类型 | 说明 |
|---|---|---|
id |
INTEGER PK | 自增主键 |
document_id |
TEXT UNIQUE | UUID v7 |
instance_id |
INTEGER FK | 关联实例 |
step_id |
TEXT | 步骤定义 ID |
step_name |
TEXT | 步骤名称(冗余,方便查询) |
status |
TEXT | running / completed / failed |
input |
TEXT? | JSON,步骤开始时的 context 快照 |
output |
TEXT? | JSON,步骤完成时的输出 |
error |
TEXT? | 错误信息(仅 failed) |
started_at |
TEXT | 开始时间 |
completed_at |
TEXT? | 完成时间 |
4. 步骤类型详解
4.1 StepDef 结构
每个步骤定义包含以下字段:
{
"id": "review",
"name": "审核",
"type": "await",
"config": {},
"next": "publish",
"timeout_ms": 0
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 步骤唯一标识,工作流内不可重复 |
name |
string | 是 | 显示名称 |
type |
string | 是 | 步骤类型:task / await / branch / parallel / delay |
config |
object | 否 | 步骤配置(各类型含义不同) |
next |
any | 否 | 下一步转移规则(各类型格式不同) |
timeout_ms |
number | 否 | 超时毫秒数(当前预留,未实现自动超时) |
4.2 Task — 自动任务
语义:系统自动执行的步骤。调用方通过 execute_step 提交结果后推进到 next。
next 格式:string,目标步骤 ID 或空字符串(表示结束)。
{
"id": "notify",
"name": "发送通知",
"type": "task",
"config": { "channel": "email" },
"next": "archive"
}
执行流程:
execute_step被调用,step_output合并到 context- 当前步骤 log 标记为
completed resolve_next_step返回next指定的步骤 ID- 实例推进到下一步
next 特殊值:
| 值 | 行为 |
|---|---|
"s2" |
推进到步骤 s2 |
"" / null |
工作流完成(status = completed) |
4.3 Await — 等待外部事件
语义:等待人工操作(如审批)或外部系统回调。与 Task 共享相同的状态转移逻辑,区别在于语义——Await 表示"需要外部触发"。
next 格式:与 Task 相同。
{
"id": "approve",
"name": "等待审批",
"type": "await",
"config": { "roles": ["admin", "editor"] },
"next": "publish"
}
执行流程:与 Task 完全一致。区分 task 和 await 的目的是让前端知道当前步骤是否需要用户交互。
4.4 Branch — 条件分支
语义:根据工作流 context 中的字段值选择下一步。
next 格式:Array<{ condition?: Object, step: string }>
condition:键值对,所有字段必须完全匹配- 无
condition的分支是 fallback(当所有条件都不匹配时) - 按数组顺序评估,第一个匹配的分支生效
{
"id": "decide",
"name": "审核结果",
"type": "branch",
"config": {},
"next": [
{ "condition": { "approved": true }, "step": "publish" },
{ "condition": { "approved": false, "reason": "reject" }, "step": "notify_reject" },
{ "step": "draft" }
]
}
条件匹配规则:
| 期望值类型 | 比较方式 |
|---|---|
| String | context[key].as_str() == expected |
| Number | context[key].as_f64() == expected.as_f64() |
| Bool | context[key].as_bool() == expected |
| null / Object / Array | 不匹配,返回 false |
所有 condition 中的字段必须同时匹配(AND 逻辑)。缺少某个字段的 context 也不匹配。
4.5 Parallel — 并行执行
语义:同时启动多个分支,所有分支完成后汇合到 join_next 或结束。
next 格式:string[](分支步骤 ID 数组)
config 字段:
| 字段 | 类型 | 说明 |
|---|---|---|
join_next |
string? |
所有分支完成后的下一步。省略则所有分支完成后直接结束工作流 |
{
"id": "parallel_notify",
"name": "并行通知",
"type": "parallel",
"config": { "join_next": "generate_report" },
"next": ["email_notify", "slack_notify"]
}
执行流程:
execute_step (Parallel)
│
┌─────────────┼─────────────┐
│ 创建所有分支的 running log │
│ context 写入 _parallel │
│ current_step = 分支[0] │
└─────────────┼─────────────┘
│
┌──────────▼──────────┐
│ execute_step │
│ (分支 A - task) │
└──────────┬──────────┘
│ 完成 A,pending 移除 A
│ remaining > 0
│ current_step = 分支 B
┌──────────▼──────────┐
│ execute_step │
│ (分支 B - task) │
└──────────┬──────────┘
│ 完成 B,pending 清空
│ remaining == 0
│ 清除 _parallel
│
┌────────▼────────┐
│ join_next 存在? │
└───┬─────────┬───┘
│ Yes │ No
▼ ▼
推进到 工作流
join_next completed
并行状态追踪:通过 context 中的 _parallel 字段实现(内部字段,API 不暴露):
{
"_parallel": {
"parent": "parallel_notify",
"pending": ["slack_notify"],
"join_next": "generate_report"
}
}
注意:当前实现为顺序执行分支(串行通过 execute_step 逐一完成),而非真正的并发执行。这是基于以下考虑:
- CMS 场景下"并行"通常是逻辑上的编排需求("这三件事都需要做"),而非性能需求
- SQLite 不支持高并发写入
- 真正的并发需要后台 worker 支持
4.6 Delay — 延迟等待
语义:等待指定时间后自动推进。
next 格式:与 Task 相同。
{
"id": "wait_24h",
"name": "等待24小时",
"type": "delay",
"config": { "duration_ms": 86400000 },
"next": "check_status"
}
当前状态:config 中预留了 duration_ms,但引擎尚未实现自动超时推进。目前 Delay 步骤的行为与 Task 相同——需要外部 execute_step 调用来推进。
5. API 参考
所有 API 位于 /api/v1/admin/workflows 前缀下。
5.1 创建工作流定义
POST /api/v1/admin/workflows
请求体:
{
"id": "content-review",
"name": "内容审核流程",
"description": "文章发布前的多级审核",
"steps": [
{ "id": "draft", "name": "起草", "type": "task", "config": {}, "next": "review" },
{ "id": "review", "name": "审核", "type": "await", "config": {}, "next": "" }
]
}
响应:
{
"code": 0,
"message": "created",
"data": { "id": 1, "document_id": "content-review", "name": "内容审核流程", ... }
}
错误码:
| 状态码 | 场景 |
|---|---|
| 400 | steps 为空、步骤引用不存在的 ID、parallel/branch 的 next 格式错误 |
5.2 列出所有定义
GET /api/v1/admin/workflows
5.3 获取单个定义
GET /api/v1/admin/workflows/{id}
5.4 删除定义
DELETE /api/v1/admin/workflows/{id}
注意:删除定义不会级联删除已有实例。
5.5 启动工作流实例
POST /api/v1/admin/workflows/{id}/start
请求体:
{
"context": { "title": "新文章", "author": "张三" },
"triggered_by": "user-doc-id-xxx"
}
响应:返回 WorkflowInstance,status = "running",current_step = initial_step。
错误码:
| 状态码 | 场景 |
|---|---|
| 400 | 工作流定义已禁用(enabled = false) |
| 404 | 工作流定义不存在 |
5.6 执行当前步骤
POST /api/v1/admin/workflows/instances/{instanceId}/execute
请求体:
{
"output": { "approved": true, "comment": "通过" }
}
行为:
output中的键值合并到工作流 context- 当前步骤 log 标记为
completed - 根据步骤类型和 context 决定下一步
错误码:
| 状态码 | 场景 |
|---|---|
| 400 | 实例不是 running 状态 |
| 404 | 实例不存在 |
5.7 取消工作流实例
POST /api/v1/admin/workflows/instances/{instanceId}/cancel
错误码:
| 状态码 | 场景 |
|---|---|
| 400 | 实例不是 running 状态 |
| 404 | 实例不存在 |
5.8 获取步骤日志
GET /api/v1/admin/workflows/instances/{instanceId}/logs
响应:
{
"code": 0,
"message": "ok",
"data": [
{
"step_id": "draft",
"step_name": "起草",
"status": "completed",
"input": "{\"title\":\"新文章\"}",
"output": "{\"title\":\"新文章\",\"content\":\"...\"}",
"started_at": "2026-05-09T10:00:00Z",
"completed_at": "2026-05-09T10:05:00Z"
}
]
}
5.9 列出工作流实例
GET /api/v1/admin/workflows/instances?definition_id=xxx&status=running&page=1&page_size=20
所有查询参数均可选。
6. 使用示例
6.1 简单审批流
起草 → 审核 → 发布
{
"id": "simple-review",
"name": "简单审批",
"steps": [
{ "id": "draft", "name": "起草", "type": "task", "config": {}, "next": "review" },
{ "id": "review", "name": "审核", "type": "await", "config": {}, "next": "publish" },
{ "id": "publish", "name": "发布", "type": "task", "config": {}, "next": "" }
]
}
6.2 条件分支流
起草 → 审核 → [通过?发布 : 驳回通知]
{
"id": "branch-review",
"name": "分支审批",
"steps": [
{ "id": "draft", "name": "起草", "type": "task", "config": {}, "next": "review" },
{
"id": "review",
"name": "审核决策",
"type": "branch",
"config": {},
"next": [
{ "condition": { "approved": true }, "step": "publish" },
{ "step": "reject" }
]
},
{ "id": "publish", "name": "发布", "type": "task", "config": {}, "next": "" },
{ "id": "reject", "name": "驳回通知", "type": "task", "config": {}, "next": "" }
]
}
调用 execute_step 时传入 output:
{ "output": { "approved": true } }
6.3 并行通知 + 汇合
┌→ 邮件通知 ─┐
提交审核 → │ │ → 生成报告
└→ Slack通知 ┘
{
"id": "parallel-notify",
"name": "并行通知",
"steps": [
{ "id": "submit", "name": "提交", "type": "task", "config": {}, "next": "notify" },
{
"id": "notify",
"name": "并行通知",
"type": "parallel",
"config": { "join_next": "report" },
"next": ["email", "slack"]
},
{ "id": "email", "name": "邮件通知", "type": "task", "config": {}, "next": "" },
{ "id": "slack", "name": "Slack通知", "type": "task", "config": {}, "next": "" },
{ "id": "report", "name": "生成报告", "type": "task", "config": {}, "next": "" }
]
}
6.4 完整内容发布流
{
"id": "content-publish",
"name": "内容发布流程",
"description": "含审核、并行通知、条件发布的完整流程",
"steps": [
{ "id": "draft", "name": "起草", "type": "task", "config": {}, "next": "review" },
{ "id": "review", "name": "编辑审核", "type": "await", "config": {}, "next": "decide" },
{
"id": "decide",
"name": "审核结果",
"type": "branch",
"config": {},
"next": [
{ "condition": { "approved": true, "priority": "high" }, "step": "urgent_publish" },
{ "condition": { "approved": true }, "step": "normal_publish" },
{ "step": "back_to_draft" }
]
},
{ "id": "urgent_publish", "name": "紧急发布", "type": "task", "config": {}, "next": "notify" },
{ "id": "normal_publish", "name": "普通发布", "type": "task", "config": {}, "next": "" },
{
"id": "notify",
"name": "通知相关人员",
"type": "parallel",
"config": { "join_next": "log" },
"next": ["notify_author", "notify_editors"]
},
{ "id": "notify_author", "name": "通知作者", "type": "task", "config": {}, "next": "" },
{ "id": "notify_editors", "name": "通知编辑组", "type": "task", "config": {}, "next": "" },
{ "id": "log", "name": "记录日志", "type": "task", "config": {}, "next": "" },
{ "id": "back_to_draft", "name": "退回修改", "type": "task", "config": {}, "next": "draft" }
]
}
7. 当前限制
7.1 已知限制
| 限制 | 说明 |
|---|---|
| Parallel 顺序执行 | 并行分支通过串行 execute_step 完成,非真正并发 |
| Delay 未实现自动超时 | 需外部调用 execute_step 推进,未接入后台定时器 |
| 条件表达式仅支持等值比较 | 不支持 >/</contains/正则等复杂条件 |
| 定义不可修改 | 创建后 steps 不可变更(需删除重建) |
| 无版本管理 | version 字段预留但未使用 |
| 无重试机制 | 步骤失败后无法自动重试 |
| 无超时告警 | timeout_ms 字段预留但未实现 |
| Context 无类型约束 | 所有值都是 serde_json::Value,无 schema 校验 |
| 取消不清理并行状态 | 并行执行中取消实例,不会标记各分支 log 为 cancelled |
7.2 性能边界
- 单实例最大步骤数:无硬限制(实际受 SQLite TEXT 列大小限制)
- 并行分支数:无硬限制(每个分支创建独立 step_log 行)
- Context 大小:受 SQLite TEXT 列限制(默认 1GB)
- 无分页的
list_workflows:定义数量大时需加分页
8. 升级路线图
按优先级分为 P0(必需)、P1(重要)、P2(增强) 三个等级。
P0:核心补全
8.1 Delay 自动超时
目标:Delay 步骤到时间后自动推进,无需外部调用。
方案:
WorkflowService::start_workflow检查初始步骤是否为 Delay,若是则注册定时器- 使用
tokio::time::sleep+tokio::spawn在后台到期后调用execute_step - Worker 调度器(
src/worker/scheduler.rs)已有定时任务框架,可复用
预估工作量:1-2 天
8.2 步骤超时检测
目标:timeout_ms > 0 的步骤在指定时间未完成时自动标记失败。
方案:
- 启动步骤时记录
started_at - Worker 定时扫描
workflow_step_logs WHERE status = 'running' AND (now - started_at) > timeout - 自动调用
fail_step
预估工作量:1 天
8.3 定义更新
目标:支持修改已有工作流定义的 steps,不影响运行中的实例。
方案:
- 新增
PUT /admin/workflows/{id}端点 - 运行中的实例继续使用启动时的 steps 快照(存储在 instance 上或首次加载时缓存)
- 新启动的实例使用最新定义
预估工作量:1 天
P1:实用功能
8.4 条件表达式增强
目标:支持比较运算符和嵌套字段。
方案:
{
"condition": {
"score": { "$gt": 80 },
"tags": { "$contains": "rust" },
"meta.region": { "$in": ["us", "eu"] }
}
}
参考 MongoDB 查询语法,实现 $gt/$lt/$gte/$lte/$in/$contains/$regex 运算符。
预估工作量:2-3 天
8.5 步骤重试
目标:失败步骤可配置自动重试。
方案:
- StepDef 新增
config.retry:{ "retry": { "max_attempts": 3, "interval_ms": 5000, "backoff": "exponential" } } fail_step检查重试配置,若未达上限则重新创建 running log- 指数退避:
interval_ms * 2^(attempt-1)
预估工作量:2 天
8.6 Parallel 真正并发
目标:并行分支真正同时执行,而非串行。
方案:
- 使用
tokio::spawn并发执行各分支 - 分支结果通过
JoinHandle收集 - 所有分支完成后才推进到
join_next
前提:需要先实现真正的后台 Task 执行能力(见 8.8)。
预估工作量:3-5 天
8.7 工作流事件
目标:工作流状态变更时发出事件,供 Webhook/通知系统消费。
方案:
- 复用现有
EventBus,新增事件类型:WorkflowStarted { instance_id, definition_id }StepCompleted { instance_id, step_id, output }StepFailed { instance_id, step_id, error }WorkflowCompleted { instance_id }WorkflowCancelled { instance_id }
- Handler 层在调用 service 后 emit 事件
预估工作量:1-2 天
P2:高级特性
8.8 Task 自动执行
目标:Task 步骤可绑定 plugin hook 或内置 action,自动执行而非等待外部 execute_step。
方案:
- StepDef config 新增
action:{ "action": "plugin:email/send", "params": { "to": "{{context.author_email}}" } } - 引擎在推进到 Task 步骤时自动调用对应 handler
- 支持
mustache模板语法从 context 中取值
预估工作量:5-7 天
8.9 子工作流
目标:步骤可嵌套调用另一个工作流。
方案:
- 新增步骤类型
SubWorkflow:{ "id": "sub", "type": "sub_workflow", "config": { "workflow_id": "approval-flow" }, "next": "..." } - 父实例等待子实例完成后获取其 output 作为自身 step output
预估工作量:3-5 天
8.10 可视化定义
目标:前端拖拽式工作流编辑器 + 后端验证。
方案:
- 前端使用 React Flow / dagre.js 绘制流程图
- 导出为现有 JSON 格式
- 后端新增
POST /admin/workflows/validate校验端点
预估工作量:前端为主,后端 1 天
8.11 版本管理
目标:工作流定义支持版本化和灰度发布。
方案:
workflow_definitions新增version自增逻辑- 实例记录
definition_version - 支持回滚到指定版本
预估工作量:2-3 天
8.12 审计与监控
目标:集成 audit_log,提供工作流运行统计面板。
方案:
- 复用
src/audit.rs,记录关键操作 - 新增统计 API:
GET /admin/workflows/stats— 定义数、运行中/完成/失败实例数GET /admin/workflows/instances/{id}/timeline— 甘特图数据
- 平均步骤耗时计算
预估工作量:2-3 天
升级优先级总览
| 优先级 | 编号 | 名称 | 工作量 | 价值 |
|---|---|---|---|---|
| P0 | 8.1 | Delay 自动超时 | 1-2 天 | 完善 Delay 语义 |
| P0 | 8.2 | 步骤超时检测 | 1 天 | 防止步骤永久卡住 |
| P0 | 8.3 | 定义更新 | 1 天 | 基础管理能力 |
| P1 | 8.4 | 条件表达式增强 | 2-3 天 | 解锁复杂业务场景 |
| P1 | 8.5 | 步骤重试 | 2 天 | 提高可靠性 |
| P1 | 8.6 | Parallel 真正并发 | 3-5 天 | 性能提升 |
| P1 | 8.7 | 工作流事件 | 1-2 天 | 可观测性 |
| P2 | 8.8 | Task 自动执行 | 5-7 天 | 真正的自动化 |
| P2 | 8.9 | 子工作流 | 3-5 天 | 流程复用 |
| P2 | 8.10 | 可视化定义 | 后端 1 天 | 用户体验 |
| P2 | 8.11 | 版本管理 | 2-3 天 | 安全变更 |
| P2 | 8.12 | 审计与监控 | 2-3 天 | 运维能力 |
建议实施顺序:8.3 → 8.1 → 8.2 → 8.7 → 8.4 → 8.5 → 8.12 → 8.8 → 8.6 → 8.11 → 8.9 → 8.10