# 003-工作流引擎设计决策

| 属性 | 说明 |
|-------|------|
| **状态** | 已接受 |
| **创建日期** | 2024-05-18 |
| **作者** | 你的名字 |

## 背景

工作流引擎是ITOps Agent Platform的核心组件。我们需要设计一个工作流系统，用于：

- 可视化编排运维任务
- 支持多种节点类型（Agent、条件判断、并行执行等
- 支持多Agent协作
- 实时反馈执行进度
- 断点续传和状态管理

## 选项

我们评估了几种工作流引擎的设计方案：

### 选项1: 基于有限状态机（FSM）

**优点：**
- 简单，容易理解
- 状态转换清晰
- 适合简单流程

**缺点：**
- 不适合复杂的嵌套和分支逻辑
- 难以支持并行执行困难
- 可视化对应可视化不太友好

### 选项2: 有向无环图（DAG）+ 事件驱动

**优点：**
- 灵活，可以灵活
- 天然支持并行执行
- 支持复杂的依赖关系

**缺点：**
- 实现复杂度较高

### 选项3: 节点- 节点模型（我们采用的方案）

基于节点类型节点+边的模型，这是工作流编排的标准模型

**优点：**
- 直观，与可视化编辑器
- 灵活，支持各种复杂流程
- 容易扩展新的节点类型

**缺点：**
- 实现起来稍复杂

## 决策

我们采用基于**节点-边模型** + **事件驱动架构** + **责任链模式**的工作流引擎。

## 设计

### 核心概念

```
工作流 (Workflow)
├── 节点 (Node)
│   ├── Agent节点 (Agent)
│   ├── 条件节点 (Condition)
│   ├── 并执行节点 (Parallel)
│   └── ...
└── 边 (Edge)
    ├── 连接两个节点
    └── 定义执行顺序

```

### 节点类型

我们定义了以下节点类型：

| 类型 | 说明 |
|------|------|
| **Agent Node | 调用Agent执行任务 |
| Condition | 根据条件选择下一个节点 |
| Parallel | 并发执行多个子流程 |
| Start | 起始节点 |
| End | 结束节点 |

### 执行模型

**状态机：

```
初始化 → 就绪 → 执行中 → 完成
                    ↓
                  失败
                    ↓
              重试（可选）
```

### 事件溯源（Event Sourcing）

我们采用事件溯源设计理念：

- 所有执行过程中所有
- 每个事件被记录到数据库
- 可以历史可以从任何时间点
- 支持和调试方便

**事件类型：

| 事件 | 说明 |
|------|------|
| `task:started` | 任务开始 |
| `node:started` | 节点开始 |
| `node:thinking` | Agent思考 |
| `node:output` | Agent输出 |
| `node:completed` | 节点完成 |
| `task:completed` | 任务完成 |
| `task:failed` | 任务失败 |

## 理由

### 1. 节点边模型直观直观

- 与 React Flow 完全，天然支持可视化
- 用户容易容易理解
- 拖拽式操作用户体验好

### 2. 事件驱动架构适合实时反馈

- WebSocket推送事件
- 前端实时显示执行进度
- 用户体验好

### 3. 灵活扩展性

- 新增节点类型很容易
- 不需要修改引擎核心
- 符合开闭原则（Open/Closed Principle

### 4. 事件溯源带来的好处

- 完整的审计日志
- 可以回放执行过程
- 调试和问题排查方便
- 支持断点续传（未来可以实现）

## 设计细节

### 工作流执行伪代码

```typescript
class WorkflowExecutor {
  async execute(workflowId, context) {
    // 1. 初始化状态
    const state = new ExecutionState()
    
    // 2. 找起始节点
    const startNode = findStartNode(workflowId)
    
    // 3. 递归执行
    await this.executeNode(startNode, context, state)
    
    // 4. 返回结果
    return state.getResult()
  }
  
  async executeNode(node, context, state) {
    // 记录事件
    state.recordEvent({ type: 'node:started', nodeId: node.id })
    
    try {
      // 执行节点
      const result = await node.execute(context)
      
      // 记录完成事件
      state.recordEvent({ 
        type: 'node:completed', nodeId: node.id, result })
      
      // 找到下一个节点
      const nextNodes = this.findNextNodes(node.id)
      
      // 继续执行
      for (const next of nextNodes) {
        await this.executeNode(next, context, state)
      }
    } catch (error) {
      // 记录错误
      state.recordEvent({ type: 'node:failed', nodeId: node.id, error })
      throw error
    }
  }
}
```

### 上下文传递

我们在执行过程中，上下文会在节点间传递：

```typescript
interface Context {
  serverId?: string
  [key: string]: any
}
```

每个节点可以读取和修改上下文，实现数据传递。

## 后果

### 正面后果

- 灵活灵活，支持复杂运维场景
- 可扩展，容易添加新功能
- 用户体验好，实时反馈
- 完整的审计日志
- 可视化友好，未来可以和

### 负面后果

- 引擎实现复杂度较高
- 需要仔细设计状态管理
- 事件存储可能导致数据量增长（但SQLite完全可以）

## 未来工作

我们计划在未来：

1. **工作流版本管理
2. **工作流模板市场
3. **支持更复杂的流程控制（循环、暂停/继续等）
4. **工作流性能优化（）

## 总结

基于节点-边模型 + 事件驱动架构是最适合我们场景的方案，灵活、可扩展、用户体验好。
