@flowlab/all
Version:
A cool library focusing on handling various flows
191 lines (155 loc) • 9.94 kB
Markdown
## 如何使用 FlowLab (统一设计版) - 中文自然语言描述
FlowLab 是一个用来帮助你定义、执行和管理复杂任务流程(工作流)的 TypeScript/JavaScript 库。它特别适合处理那些包含多个步骤、需要条件判断、可能需要重试或与其他系统交互的业务逻辑。以下是如何使用这个新版 FlowLab 库的基本步骤:
**第一步:初始化 FlowLab 引擎**
首先,你需要创建一个 `FlowLabEngine` 的实例。这是你与 FlowLab 交互的主要入口。
```typescript
import { FlowLabEngine, ConsoleLogger } from './flowlab/src'; // 假设你的库代码在 flowlab/src
// 创建引擎实例,可以传入配置选项
const engine = new FlowLabEngine({
logger: new ConsoleLogger('[MyWorkflowApp]'), // 使用控制台打印日志
// 如果需要持久化工作流状态(比如长时间运行的流程或故障恢复),可以配置持久化服务
// persistence: new MemoryPersistence(), // 使用内存持久化 (适合开发测试)
// persistence: new RedisPersistence('redis://...'), // 或使用 Redis (适合生产)
// 如果需要延迟执行或分布式任务,可以配置调度器和事件管理器
// scheduler: new LocalScheduler(...),
// eventManager: new InMemoryEventManager(),
});
```
引擎会管理所有的节点、工作流定义以及配置。你可以在创建时传入自定义的日志记录器、
持久化存储方案、任务调度器和事件管理器,如果省略,它会使用一些默认的简单实现(比如打印日志到控制台)。
**第二步:定义你的任务节点 (Node)**
工作流中的每个具体操作(比如调用 API、查询数据库、处理数据、调用 AI 模型等)都需要定义为一个“节点”。你有两种方式定义节点:
1. **简单函数节点 (适用于简单、无状态的任务):**
直接注册一个异步函数。函数会接收一个 `context` 对象作为参数,你可以通过 `context.input` 获取输入,通过 `context.output = ...` 设置输出,或者通过 `context.getVariable`/`setVariable` 读写工作流变量。
```typescript
// 注册一个名为 'fetch-user' 的节点
engine.registerNode('fetch-user', async (context) => {
const userId = context.input.id;
context.log(`正在获取用户 ${userId} 的数据...`);
// 模拟 API 调用
await new Promise(res => setTimeout(res, 100));
// 将结果设置到输出
context.output = { name: `用户${userId}`, email: `${userId}@example.com` };
}, '获取用户信息的节点'); // 可以加个描述
```
2. **基于类的节点 (适用于复杂、有状态、需要验证或补偿逻辑的任务):**
创建一个类,让它继承自 `BaseNode`,并实现 `metadata` (包含节点 ID) 和 `execute` 方法。这种方式更结构化,适合封装复杂的逻辑。
```typescript
import { BaseNode, INodeContext, NodeStatus } from './flowlab/src';
class ProcessDataNode extends BaseNode {
// 定义节点元数据 (ID 必须)
readonly metadata = { id: 'process-data', description: '处理用户分数' };
// 实现核心执行逻辑
async execute(context: INodeContext): Promise<void> {
const score = context.input.score;
context.log(`处理分数: ${score}`);
const level = score > 80 ? '优秀' : score > 60 ? '良好' : '一般';
context.output = { level }; // 设置输出
context.setVariable('userLevel', level); // 设置工作流变量
}
// (可选) 实现输入验证
validate(context: INodeContext): void {
if (typeof context.input.score !== 'number') {
throw new Error('输入分数必须是数字'); // 抛出错误会使节点执行失败
}
}
// (可选) 实现补偿逻辑 (如果需要回滚)
// async compensate(context: INodeContext): Promise<void> { ... }
}
// 注册节点类的实例
engine.registerNode(new ProcessDataNode());
```
**第三步:定义你的工作流 (Workflow Definition)**
使用 `engine.defineWorkflow('工作流ID')` 开始定义一个工作流,然后通过链式调用添加各种步骤:
* **`addStep(config)`:** 添加一个执行节点的任务步骤。你需要提供步骤 `id`、要执行的 `nodeId`,以及可选的 `nextStepId`(下一步)、`input`(静态输入)、`inputMapping`(动态输入映射)、`outputMapping`(输出映射)、`retryOptions`(重试配置)、`timeoutMs`(超时)。
* **`addCondition(config)`:** 添加一个条件分支步骤。你需要提供 `id`、一个返回布尔值或分支名称的 `condition` 函数,以及一个 `branches` 对象,将条件结果映射到不同的 `nextStepId`。
* **`addParallel(config)`:** 添加一个并行步骤。`parallelSteps` 数组里包含需要并行执行的步骤配置。`nextStepId` 指向所有并行分支完成后执行的步骤。
* **`addSubWorkflow(config)`:** 添加一个子工作流步骤。需要提供 `subWorkflowId`(要调用的子流程 ID)。
* **`setStartStep('步骤ID')`:** 指定工作流从哪个步骤开始执行。
```typescript
// 定义一个工作流
const definition = engine.defineWorkflow('user-approval', '用户审批流程')
.addStep({ // 第一个任务步骤
id: 'fetch',
nodeId: 'fetch-user', // 执行我们上面注册的函数节点
inputMapping: { 'id': 'input.userId' }, // 将工作流初始输入的 userId 映射给节点的 id 输入
nextStepId: 'process' // 下一步是 process
})
.addStep({ // 第二个任务步骤
id: 'process',
nodeId: 'process-data', // 执行我们上面注册的类节点
inputMapping: { 'score': 'steps.fetch.output.score' }, // 假设 fetch-user 节点输出score
// 注意: steps.stepId.output 映射需要引擎实现支持
// 更可靠的方式是在 fetch 步骤用 outputMapping 将 score 存入变量
// 例如: outputMapping: { 'variables.currentScore': 'output.score' }
// 然后这里用: inputMapping: { 'score': 'variables.currentScore' }
outputMapping: { 'variables.finalLevel': 'output.level' }, // 将 process-data 的输出 level 存入变量 finalLevel
nextStepId: 'checkLevel' // 下一步是 checkLevel
})
.addCondition({ // 条件步骤
id: 'checkLevel',
condition: (context) => context.variables.finalLevel === '优秀', // 检查变量 finalLevel
branches: {
'true': 'autoApprove', // 如果是'优秀', 跳到 autoApprove
'false': 'manualReview' // 否则跳到 manualReview
}
})
.addStep({ // '优秀'分支的目标步骤
id: 'autoApprove',
nodeId: 'simple-log', // 用一个日志节点模拟自动批准
input: { message: '用户自动批准!' }
// 这个分支结束
})
.addStep({ // '非优秀'分支的目标步骤
id: 'manualReview',
nodeId: 'simple-log', // 用日志节点模拟人工审核
input: { message: '用户需要人工审核。' }
// 这个分支也结束
})
.setStartStep('fetch'); // 设置 'fetch' 为起始步骤
// (可选) 如果希望通过 ID 执行或持久化这个定义,需要显式注册
engine.registerDefinition(definition);
```
**第四步:执行工作流**
工作流定义好之后,你需要创建一个 `WorkflowExecutor` 来执行它。
1. **创建执行器:**
```typescript
const executor = engine.createExecutor();
```
2. **运行工作流:**
你可以通过**工作流定义实例**或**注册的 ID**来运行。
```typescript
// 定义初始输入数据
const initialData = { userId: 'abc-123' };
// 定义附加的上下文信息 (可选)
const contextExtras = { tenantId: 'my-company', userRole: 'operator' };
// 运行方式一:使用 WorkflowDefinition 实例
// const resultContext = await executor.run(definition, initialData, contextExtras);
// 运行方式二:使用注册的 ID (前提是已调用 engine.registerDefinition)
const resultContext = await executor.runById('user-approval', initialData, contextExtras);
// 检查最终结果
console.log('工作流最终状态:', resultContext.status); // e.g., COMPLETED, FAILED
console.log('工作流最终输出:', resultContext.output); // 工作流的最终输出 (如果有)
console.log('工作流最终变量:', resultContext.variables); // 所有工作流变量的最终值
// console.log('工作流执行历史:', resultContext.history); // 查看详细步骤历史
```
3. **(快捷方式) `engine.runWorkflow(...)`:** 对于简单的、一次性的流程,可以直接用这个方法,它会帮你临时创建定义并执行。
```typescript
const simpleResult = await engine.runWorkflow(
(wf) => { // 在回调里定义流程
wf.addStep({ id: 'log', nodeId: 'simple-log', input: { message: '快捷执行!' } })
.setStartStep('log');
},
{} // 初始输入
);
console.log('快捷流程状态:', simpleResult.status);
```
**核心概念总结:**
* **Engine (引擎):** 管理一切的中心。
* **Node (节点):** 执行具体任务的单元 (函数或类)。
* **Workflow Definition (工作流定义):** 描述任务流程的蓝图 (步骤、连接、条件)。
* **Workflow Instance (工作流实例):** 一次具体的执行过程,有自己的 ID、状态、变量和历史。
* **Executor (执行器):** 负责根据定义运行实例。
* **Context (上下文):** 存储实例的运行时数据 (输入、变量、状态、日志等)。
* **Mapping (映射):** 控制数据如何在工作流变量和节点输入/输出之间流动的关键机制。
通过以上步骤,你就可以使用 FlowLab 来构建、管理和执行你的业务流程了。对于更复杂的场景,你可以深入研究并行处理、子流程、事件驱动、持久化和调度等高级功能。