UNPKG

@flowlab/all

Version:

A cool library focusing on handling various flows

191 lines (155 loc) 9.94 kB
## 如何使用 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 来构建、管理和执行你的业务流程了。对于更复杂的场景,你可以深入研究并行处理、子流程、事件驱动、持久化和调度等高级功能。