1. 为什么我们需要运行时构建事件流?
当我们在开发复杂业务系统时,经常会遇到这样的场景:可视化编辑器提供的功能已经无法满足我们的需求。比如在一个电商系统中,当用户下单后需要触发一系列复杂的后续操作——库存扣减、优惠券核销、物流单生成、积分计算、消息通知等。这些操作之间往往存在复杂的依赖关系和条件判断。
可视化编辑器虽然直观,但在处理以下情况时会显得力不从心:
- 需要动态生成流程分支
- 要根据运行时数据决定后续步骤
- 需要处理复杂的异常恢复逻辑
- 流程需要频繁变更且不能停机
这时,我们就需要转向程序化的事件流构建方式。通过代码来动态构建和调整事件流,可以获得更大的灵活性和控制力。
提示:不要一上来就考虑用代码实现所有逻辑,可视化编辑器+程序化扩展的组合往往是最佳实践。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心概念解析:TriggerHandle与ChainHandle
2.1 TriggerHandle:事件触发器
TriggerHandle是事件流的起点,它负责监听和捕获特定的事件。常见的实现方式包括:
- 数据库变更监听
- API调用拦截
- 消息队列消费
- 定时任务触发
一个典型的TriggerHandle定义如下(以TypeScript为例):
typescript复制interface TriggerHandle<T> {
// 唯一标识符
id: string;
// 触发条件判断
predicate: (context: T) => boolean;
// 触发时执行的回调
onTrigger: (context: T) => Promise<void>;
// 错误处理
onError?: (error: Error) => void;
}
2.2 ChainHandle:处理链节点
ChainHandle构成了事件流的处理单元,每个节点负责特定的业务逻辑。关键特性包括:
- 支持同步/异步处理
- 可以修改上下文数据
- 可以决定是否继续后续处理
- 支持重试和回滚
ChainHandle的典型实现:
typescript复制interface ChainHandle<T> {
// 处理优先级
priority: number;
// 是否启用
enabled: boolean;
// 处理逻辑
execute: (context: T) => Promise<boolean>;
// 补偿逻辑(用于回滚)
compensate?: (context: T) => Promise<void>;
}
3. 运行时构建事件流的实现模式
3.1 声明式构建
这种模式适合流程相对固定的场景。我们预先定义好处理链的模板,在运行时根据条件动态选择模板并填充参数。
typescript复制// 定义流程模板
const orderProcessTemplate = {
triggers: ['order.created'],
chains: [
{name: 'inventory', condition: ctx => !ctx.isVirtualProduct},
{name: 'coupon', condition: ctx => ctx.couponUsed},
{name: 'notification', always: true}
]
};
// 运行时构建
function buildRuntimeFlow(order) {
const flow = cloneDeep(orderProcessTemplate);
flow.chains = flow.chains.filter(chain =>
chain.condition ? chain.condition(order) : true
);
return flow;
}
3.2 编程式构建
对于需要高度动态化的场景,我们可以完全通过代码来构建事件流:
typescript复制class FlowBuilder {
private triggers: TriggerHandle[] = [];
private chains: ChainHandle[] = [];
addTrigger(trigger: TriggerHandle) {
this.triggers.push(trigger);
return this;
}
addChain(chain: ChainHandle) {
this.chains.push(chain);
return this;
}
build() {
return {
triggers: this.triggers,
chains: this.chains.sort((a, b) => a.priority - b.priority)
};
}
}
// 使用示例
const flow = new FlowBuilder()
.addTrigger(orderCreatedTrigger)
.addChain(inventoryChain)
.addChain(couponChain)
.build();
3.3 混合式构建
结合声明式和编程式的优点,我们可以创建更灵活的解决方案:
typescript复制function createDynamicFlow(config: FlowConfig, runtimeData: any) {
const builder = new FlowBuilder();
// 添加基础触发器
builder.addTrigger(config.baseTrigger);
// 动态添加处理链
for (const chainDef of config.chainDefinitions) {
if (shouldIncludeChain(chainDef, runtimeData)) {
const chain = createChain(chainDef, runtimeData);
builder.addChain(chain);
}
}
return builder.build();
}
4. 高级应用场景与实现技巧
4.1 条件分支与动态路由
在订单处理流程中,不同类型的订单可能需要不同的处理链:
typescript复制function buildOrderFlow(order) {
const builder = new FlowBuilder();
// 基础触发器
builder.addTrigger(orderCreatedTrigger);
// 根据订单类型添加不同处理链
if (order.type === 'physical') {
builder.addChain(inventoryChain)
.addChain(shippingChain);
} else if (order.type === 'digital') {
builder.addChain(licenseChain);
}
// 通用链
builder.addChain(notificationChain);
return builder.build();
}
4.2 流程监控与调试
运行时构建的事件流需要强大的监控能力:
typescript复制interface FlowMonitor {
// 记录流程执行轨迹
trace: (event: TraceEvent) => void;
// 获取当前流程状态
getState: () => FlowState;
// 重放特定流程
replay: (flowId: string) => Promise<void>;
}
// 使用装饰器模式增强ChainHandle
function withMonitoring(chain: ChainHandle): ChainHandle {
return {
...chain,
async execute(context) {
const startTime = Date.now();
monitor.trace({
type: 'chain_start',
chainId: chain.id,
timestamp: startTime
});
try {
const result = await chain.execute(context);
monitor.trace({
type: 'chain_end',
chainId: chain.id,
duration: Date.now() - startTime,
success: true
});
return result;
} catch (error) {
monitor.trace({
type: 'chain_end',
chainId: chain.id,
duration: Date.now() - startTime,
success: false,
error
});
throw error;
}
}
};
}
4.3 错误处理与恢复
健壮的事件流需要完善的错误处理机制:
typescript复制class ResilientFlow {
private chains: ChainHandle[];
private currentIndex = 0;
constructor(chains: ChainHandle[]) {
this.chains = chains;
}
async execute(context: any) {
while (this.currentIndex < this.chains.length) {
const chain = this.chains[this.currentIndex];
try {
const shouldContinue = await chain.execute(context);
if (!shouldContinue) break;
this.currentIndex++;
} catch (error) {
if (chain.compensate) {
await chain.compensate(context);
}
throw error;
}
}
}
async retry(context: any) {
if (this.currentIndex > 0) {
this.currentIndex--;
return this.execute(context);
}
}
}
5. 性能优化实践
5.1 懒加载处理链
对于大型系统,不是所有处理链都需要立即加载:
typescript复制class LazyChainHandle implements ChainHandle {
private loader: () => Promise<ChainHandle>;
private instance: ChainHandle | null = null;
constructor(loader: () => Promise<ChainHandle>) {
this.loader = loader;
}
async execute(context: any) {
if (!this.instance) {
this.instance = await this.loader();
}
return this.instance.execute(context);
}
}
// 使用示例
const lazyChain = new LazyChainHandle(
() => import('./complexChain').then(m => m.default)
);
5.2 并行处理优化
当处理链之间没有依赖关系时,可以并行执行:
typescript复制async function executeParallelChains(chains: ChainHandle[], context: any) {
const results = await Promise.allSettled(
chains.map(chain => chain.execute(context))
);
const failed = results.filter(r => r.status === 'rejected');
if (failed.length > 0) {
// 执行补偿逻辑
await executeCompensations(chains, context);
throw new AggregateError(failed.map(f => (f as PromiseRejectedResult).reason));
}
return results.every(r =>
r.status === 'fulfilled' && r.value !== false
);
}
5.3 缓存策略
对于计算密集型的处理链,可以引入缓存:
typescript复制function withCache(chain: ChainHandle, cache: CacheStore): ChainHandle {
return {
...chain,
async execute(context) {
const cacheKey = createCacheKey(chain.id, context);
const cached = await cache.get(cacheKey);
if (cached) return cached;
const result = await chain.execute(context);
await cache.set(cacheKey, result);
return result;
}
};
}
6. 测试与验证策略
6.1 单元测试处理链
每个ChainHandle应该独立可测试:
typescript复制describe('InventoryChain', () => {
let chain: ChainHandle;
let mockInventoryService: jest.Mocked<InventoryService>;
beforeEach(() => {
mockInventoryService = {
deduct: jest.fn().mockResolvedValue(true)
};
chain = new InventoryChain(mockInventoryService);
});
it('should deduct inventory for physical products', async () => {
const context = { productType: 'physical', productId: '123', quantity: 1 };
const result = await chain.execute(context);
expect(result).toBe(true);
expect(mockInventoryService.deduct).toHaveBeenCalledWith('123', 1);
});
});
6.2 流程集成测试
测试完整的事件流执行:
typescript复制describe('OrderFlow', () => {
let flowBuilder: FlowBuilder;
beforeEach(() => {
flowBuilder = new FlowBuilder();
// 设置测试用的触发器和处理链
});
it('should process physical order correctly', async () => {
const flow = flowBuilder.build();
const trigger = flow.triggers.find(t => t.id === 'order.created');
const testContext = { orderType: 'physical' };
await trigger.onTrigger(testContext);
// 验证处理链的执行结果
expect(testContext).toHaveProperty('inventoryUpdated', true);
expect(testContext).toHaveProperty('shippingScheduled', true);
});
});
6.3 混沌测试
模拟异常情况下的流程行为:
typescript复制describe('FlowResilience', () => {
it('should compensate when chain fails', async () => {
const failingChain = {
execute: jest.fn().mockRejectedValue(new Error('Failed')),
compensate: jest.fn().mockResolvedValue(undefined)
};
const flow = new ResilientFlow([failingChain]);
await expect(flow.execute({})).rejects.toThrow();
expect(failingChain.compensate).toHaveBeenCalled();
});
});
7. 实际案例:电商订单处理系统
让我们通过一个电商订单处理的完整示例,展示如何应用运行时事件流构建技术。
7.1 定义触发器
typescript复制const orderCreatedTrigger: TriggerHandle<OrderContext> = {
id: 'order.created',
predicate: (context) => context.eventType === 'ORDER_CREATED',
async onTrigger(context) {
// 初始化处理上下文
context.flowId = generateFlowId();
context.startTime = Date.now();
// 构建并执行处理流
const flow = buildOrderFlow(context.order);
await executeFlow(flow, context);
},
onError(error) {
alertError(`Order processing failed: ${error.message}`);
}
};
7.2 定义处理链
typescript复制// 库存扣减链
const inventoryChain: ChainHandle<OrderContext> = {
priority: 100,
enabled: true,
async execute(context) {
const { order } = context;
if (order.items.every(i => i.type !== 'physical')) {
return true; // 跳过虚拟商品
}
try {
await inventoryService.deductStock(
order.items.map(i => ({ id: i.productId, quantity: i.quantity }))
);
context.inventoryUpdated = true;
return true;
} catch (error) {
context.inventoryError = error;
throw error;
}
},
async compensate(context) {
if (context.inventoryUpdated) {
await inventoryService.restoreStock(
context.order.items.map(i => ({ id: i.productId, quantity: i.quantity }))
);
}
}
};
// 优惠券核销链
const couponChain: ChainHandle<OrderContext> = {
priority: 200,
enabled: true,
async execute(context) {
if (!context.order.couponCode) return true;
const result = await couponService.redeem(
context.order.userId,
context.order.couponCode
);
context.couponRedeemed = true;
return result.success;
},
async compensate(context) {
if (context.couponRedeemed) {
await couponService.restore(
context.order.userId,
context.order.couponCode
);
}
}
};
7.3 运行时流程构建
typescript复制function buildOrderFlow(order: Order): Flow {
const builder = new FlowBuilder();
// 基础处理链
builder.addChain(inventoryChain)
.addChain(couponChain)
.addChain(paymentChain);
// 动态添加物流链
if (hasPhysicalProducts(order)) {
builder.addChain(shippingChain);
// 根据配送地址添加特殊处理
if (isRemoteArea(order.shippingAddress)) {
builder.addChain(remoteShippingChain);
}
}
// 添加通知链
builder.addChain(notificationChain);
return builder.build();
}
7.4 流程执行引擎
typescript复制async function executeFlow(flow: Flow, context: any) {
const executor = new FlowExecutor(flow);
try {
await executor.execute(context);
monitor.recordSuccess(flow, context);
} catch (error) {
monitor.recordFailure(flow, context, error);
await executor.compensate(context);
throw error;
}
}
class FlowExecutor {
constructor(private flow: Flow) {}
async execute(context: any) {
for (const chain of this.flow.chains) {
if (!chain.enabled) continue;
const shouldContinue = await chain.execute(context);
if (!shouldContinue) break;
}
}
async compensate(context: any) {
// 逆序执行补偿逻辑
for (let i = this.flow.chains.length - 1; i >= 0; i--) {
const chain = this.flow.chains[i];
if (chain.compensate) {
await chain.compensate(context);
}
}
}
}
8. 架构设计考量
8.1 状态管理
复杂的事件流需要维护执行状态:
typescript复制interface FlowState {
flowId: string;
currentChain?: string;
completedChains: string[];
failedChains: string[];
contextData: any;
createdAt: Date;
updatedAt: Date;
}
class StatefulFlowExecutor {
private state: FlowState;
constructor(private flow: Flow, initialState?: Partial<FlowState>) {
this.state = {
flowId: generateId(),
completedChains: [],
failedChains: [],
contextData: {},
createdAt: new Date(),
updatedAt: new Date(),
...initialState
};
}
async execute() {
for (const chain of this.flow.chains) {
this.state.currentChain = chain.id;
this.state.updatedAt = new Date();
try {
const shouldContinue = await chain.execute(this.state.contextData);
this.state.completedChains.push(chain.id);
if (!shouldContinue) break;
} catch (error) {
this.state.failedChains.push(chain.id);
throw error;
}
}
}
getState() {
return this.state;
}
}
8.2 分布式执行
对于跨服务的流程,需要分布式协调:
typescript复制class DistributedFlowCoordinator {
constructor(private flowRepo: FlowRepository,
private messageQueue: MessageQueue) {}
async startFlow(flowId: string) {
const flow = await this.flowRepo.get(flowId);
await this.messageQueue.publish('flow.started', {
flowId,
firstChain: flow.chains[0].id
});
}
async handleChainCompletion(chainId: string, result: any) {
const flowId = result.flowId;
const flow = await this.flowRepo.get(flowId);
const nextChain = this.findNextChain(flow, chainId);
if (nextChain) {
await this.messageQueue.publish('chain.triggered', {
flowId,
chainId: nextChain.id,
context: result.context
});
} else {
await this.messageQueue.publish('flow.completed', {
flowId,
context: result.context
});
}
}
}
8.3 版本控制与迁移
处理流程的版本迭代:
typescript复制class FlowVersionManager {
private versions: Map<string, Flow> = new Map();
registerVersion(version: string, flow: Flow) {
this.versions.set(version, flow);
}
migrate(context: any, fromVersion?: string) {
const targetVersion = this.determineTargetVersion(context);
if (!fromVersion) {
return this.versions.get(targetVersion);
}
const migrationPath = this.findMigrationPath(fromVersion, targetVersion);
for (const step of migrationPath) {
step.migrate(context);
}
return this.versions.get(targetVersion);
}
}
9. 性能监控与指标收集
9.1 关键指标定义
typescript复制interface FlowMetrics {
// 流程执行时间
duration: number;
// 各链执行时间
chainDurations: Record<string, number>;
// 成功率
successRate: number;
// 错误统计
errorStatistics: {
chainErrors: Record<string, number>;
systemErrors: number;
businessErrors: number;
};
// 吞吐量
throughput: number;
}
9.2 监控实现
typescript复制class FlowMonitor {
private metrics: FlowMetrics = {
duration: 0,
chainDurations: {},
successRate: 0,
errorStatistics: {
chainErrors: {},
systemErrors: 0,
businessErrors: 0
},
throughput: 0
};
private timers: Record<string, number> = {};
startTimer(flowId: string) {
this.timers[flowId] = Date.now();
}
recordChainStart(chainId: string) {
this.timers[chainId] = Date.now();
}
recordChainEnd(chainId: string, success: boolean) {
const duration = Date.now() - this.timers[chainId];
this.metrics.chainDurations[chainId] =
(this.metrics.chainDurations[chainId] || 0) + duration;
if (!success) {
this.metrics.errorStatistics.chainErrors[chainId] =
(this.metrics.errorStatistics.chainErrors[chainId] || 0) + 1;
}
}
recordFlowEnd(flowId: string, success: boolean) {
this.metrics.duration = Date.now() - this.timers[flowId];
if (success) {
this.metrics.successRate = ((this.metrics.successRate * 99) + 1) / 100;
} else {
this.metrics.successRate = (this.metrics.successRate * 99) / 100;
}
}
getMetrics() {
return this.metrics;
}
}
9.3 可视化仪表盘
将监控数据通过Grafana等工具展示:
typescript复制function setupFlowDashboard(monitor: FlowMonitor) {
setInterval(() => {
const metrics = monitor.getMetrics();
dashboard.update({
'flow.duration': metrics.duration,
'flow.success_rate': metrics.successRate,
'flow.throughput': metrics.throughput,
...Object.entries(metrics.chainDurations).reduce((acc, [chain, duration]) => {
acc[`chain.${chain}.duration`] = duration;
return acc;
}, {}),
...Object.entries(metrics.errorStatistics.chainErrors).reduce((acc, [chain, count]) => {
acc[`chain.${chain}.errors`] = count;
return acc;
}, {})
});
}, 5000);
}
10. 安全考量与实践
10.1 上下文数据安全
typescript复制function sanitizeContext(context: any) {
const safeContext = { ...context };
// 移除敏感信息
delete safeContext.userPassword;
delete safeContext.creditCardInfo;
delete safeContext.apiKeys;
// 加密敏感数据
if (safeContext.personalInfo) {
safeContext.personalInfo = encrypt(safeContext.personalInfo);
}
return safeContext;
}
class SecureChainHandle implements ChainHandle {
constructor(private chain: ChainHandle) {}
async execute(context: any) {
const safeContext = sanitizeContext(context);
return this.chain.execute(safeContext);
}
}
10.2 权限控制
typescript复制class AuthorizedFlowBuilder {
constructor(private user: User, private builder: FlowBuilder) {}
addChain(chain: ChainHandle) {
if (!this.user.hasPermission(`chain.${chain.id}.execute`)) {
throw new Error('Unauthorized chain');
}
this.builder.addChain(chain);
return this;
}
build() {
return this.builder.build();
}
}
10.3 防篡改机制
typescript复制function withIntegrityCheck(flow: Flow): Flow {
const hash = createHash(JSON.stringify(flow));
return {
...flow,
verifyIntegrity() {
const currentHash = createHash(JSON.stringify({
triggers: flow.triggers,
chains: flow.chains
}));
return currentHash === hash;
}
};
}
11. 调试与问题排查
11.1 日志记录策略
typescript复制interface FlowLog {
timestamp: Date;
level: 'debug' | 'info' | 'warn' | 'error';
message: string;
context?: any;
chainId?: string;
flowId?: string;
}
class FlowLogger {
private logs: FlowLog[] = [];
log(log: Omit<FlowLog, 'timestamp'>) {
this.logs.push({
timestamp: new Date(),
...log
});
}
getLogs(filter?: Partial<FlowLog>) {
return filter
? this.logs.filter(log => matchesFilter(log, filter))
: this.logs;
}
dumpToFile(filename: string) {
fs.writeFileSync(filename, JSON.stringify(this.logs, null, 2));
}
}
// 使用示例
const logger = new FlowLogger();
logger.log({
level: 'info',
message: 'Flow execution started',
flowId: '123'
});
11.2 断点调试支持
typescript复制class DebuggableFlowExecutor {
private breakpoints = new Set<string>();
constructor(private executor: FlowExecutor) {}
addBreakpoint(chainId: string) {
this.breakpoints.add(chainId);
}
async execute(context: any) {
for (const chain of this.executor.flow.chains) {
if (this.breakpoints.has(chain.id)) {
await this.waitForDebugger(chain.id, context);
}
await chain.execute(context);
}
}
private async waitForDebugger(chainId: string, context: any) {
return new Promise(resolve => {
debugServer.waitForContinue(chainId, () => {
debugServer.sendContext(chainId, context);
resolve();
});
});
}
}
11.3 问题排查指南
常见问题及解决方案:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 流程卡在某个链 | 链执行超时 | 检查链的超时设置,增加超时阈值 |
| 上下文数据丢失 | 链修改了共享上下文 | 使用不可变上下文,或深度克隆对象 |
| 补偿逻辑未执行 | 异常未被正确捕获 | 确保所有异步操作都有try-catch |
| 流程重复执行 | 触发器多次触发 | 添加幂等性检查,使用唯一ID |
12. 与可视化编辑器的集成
12.1 导出为可执行代码
将可视化编辑器设计的流程导出为可执行的程序化流程:
typescript复制class FlowExporter {
exportToCode(visualFlow: VisualFlow): string {
let code = 'const builder = new FlowBuilder();\n\n';
// 添加触发器
code += `// Triggers\n`;
visualFlow.triggers.forEach(trigger => {
code += `builder.addTrigger(${this.exportTrigger(trigger)});\n`;
});
// 添加处理链
code += `\n// Chains\n`;
visualFlow.chains.forEach(chain => {
code += `builder.addChain(${this.exportChain(chain)});\n`;
});
code += '\nreturn builder.build();';
return code;
}
private exportTrigger(trigger: VisualTrigger): string {
return `{
id: '${trigger.id}',
predicate: ${trigger.condition || '() => true'},
onTrigger: async (ctx) => {
${trigger.actions.join('\n')}
}
}`;
}
}
12.2 导入可视化编辑器
将程序化流程导入可视化编辑器:
typescript复制class FlowImporter {
importFromCode(code: string): VisualFlow {
const ast = parseCodeToAST(code);
const visualFlow: VisualFlow = {
triggers: [],
chains: []
};
ast.findCalls('addTrigger').forEach(call => {
visualFlow.triggers.push(this.createVisualTrigger(call.arguments));
});
ast.findCalls('addChain').forEach(call => {
visualFlow.chains.push(this.createVisualChain(call.arguments));
});
return visualFlow;
}
}
12.3 双向同步机制
保持可视化设计和程序化代码的同步:
typescript复制class FlowSynchronizer {
private visualFlow: VisualFlow;
private programmaticFlow: Flow;
constructor(private editor: VisualEditor, private builder: FlowBuilder) {}
async syncFromVisual() {
this.visualFlow = this.editor.getCurrentFlow();
this.programmaticFlow = this.builder.build();
const differences = this.findDifferences();
if (differences.length > 0) {
await this.applyDifferences(differences);
}
}
async syncFromCode() {
this.programmaticFlow = this.builder.build();
this.visualFlow = this.editor.getCurrentFlow();
const differences = this.findDifferences();
if (differences.length > 0) {
await this.editor.applyChanges(differences);
}
}
}
13. 扩展性与插件系统
13.1 插件架构设计
typescript复制interface FlowPlugin {
// 插件名称
name: string;
// 在流程构建时调用
onBuild?: (flow: Flow) => void;
// 在链执行前调用
onBeforeExecute?: (chain: ChainHandle, context: any) => void;
// 在链执行后调用
onAfterExecute?: (chain: ChainHandle, context: any, result: any) => void;
// 在错误发生时调用
onError?: (error: Error, chain?: ChainHandle) => void;
}
class PluginManager {
private plugins: FlowPlugin[] = [];
register(plugin: FlowPlugin) {
this.plugins.push(plugin);
}
applyBuildHooks(flow: Flow) {
this.plugins.forEach(plugin => {
plugin.onBuild?.(flow);
});
}
applyBeforeExecuteHooks(chain: ChainHandle, context: any) {
this.plugins.forEach(plugin => {
plugin.onBeforeExecute?.(chain, context);
});
}
}
13.2 常用插件示例
日志插件
typescript复制class LoggingPlugin implements FlowPlugin {
name = 'logging';
onBuild(flow: Flow) {
console.log(`Flow built with ${flow.chains.length} chains`);
}
onBeforeExecute(chain: ChainHandle) {
console.log(`Executing chain: ${chain.id}`);
}
}
性能监控插件
typescript复制class PerformancePlugin implements FlowPlugin {
private metrics: Record<string, number> = {};
name = 'performance';
onBeforeExecute(chain: ChainHandle) {
this.metrics[`${chain.id}.start`] = Date.now();
}
onAfterExecute(chain: ChainHandle) {
const duration = Date.now() - this.metrics[`${chain.id}.start`];
console.log(`Chain ${chain.id} took ${duration}ms`);
}
}
缓存插件
typescript复制class CachePlugin implements FlowPlugin {
constructor(private cache: Cache) {}
name = 'cache';
onBeforeExecute(chain: ChainHandle, context: any) {
const cached = this.cache.get(this.getCacheKey(chain, context));
if (cached) {
context.cachedResult = cached;
}
}
onAfterExecute(chain: ChainHandle, context: any, result: any) {
this.cache.set(this.getCacheKey(chain, context), result);
}
}
14. 测试策略与质量保障
14.1 单元测试
typescript复制describe('InventoryChain', () => {
let chain: InventoryChain;
let mockInventory: jest.Mocked<InventoryService>;
beforeEach(() => {
mockInventory = {
deduct: jest.fn(),
restore: jest.fn()
};
chain = new InventoryChain(mockInventory);
});
it('should deduct inventory for physical products', async () => {
mockInventory.deduct.mockResolvedValue(true);
const result = await chain.execute({
items: [{ productId: '1', type: 'physical', quantity: 1 }]
});
expect(result).toBe(true);
expect(mockInventory.deduct).toHaveBeenCalledWith([{ id: '1', quantity: 1 }]);
});
it('should skip virtual products', async () => {
const result = await chain.execute({
items: [{ productId: '2', type: 'virtual', quantity: 1 }]
});
expect(result).toBe(true);
expect(mockInventory.deduct).not.toHaveBeenCalled();
});
});
14.2 集成测试
typescript复制describe('OrderFlowIntegration', () => {
let flowBuilder: FlowBuilder;
beforeEach(() => {
flowBuilder = new FlowBuilder()
.addTrigger(orderCreatedTrigger)
.addChain(new InventoryChain(mockInventory))
.addChain(new CouponChain(mockCoupon));
});
it('should process order with physical product and coupon', async () => {
const flow = flowBuilder.build();
const context = {
eventType: 'ORDER_CREATED',
order: {
items: [{ productId: '1', type: 'physical', quantity: 1 }],
couponCode: 'SUMMER2023'
}
};
await flow.triggers[0].onTrigger(context);
expect(context.inventoryUpdated).toBe(true);
expect(context.couponRedeemed).toBe(true);
});
});
14.3 混沌测试
typescript复制describe('FlowResilience', () => {
it('should handle inventory service failure', async () => {
mockInventory.deduct.mockRejectedValue(new Error('Service unavailable'));
const flow = new FlowBuilder()
.addChain(new InventoryChain(mockInventory))
.build();
await expect(
new FlowExecutor(flow).execute({
items: [{ productId: '1', type: 'physical', quantity: 1 }]
})
).rejects.toThrow();
// Verify compensation was called
expect(mockInventory.restore).toHaveBeenCalled();
});
});
15. 部署与运维实践
15.1 容器化部署
dockerfile复制FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY dist/ ./dist/
COPY flows/ ./flows/
ENV NODE_ENV=production
CMD ["node", "dist/server.js"]
15.2 流程热更新
typescript复制class HotFlowManager {
private flows = new Map<string, Flow>();
private watcher: fs.FSWatcher;
constructor(private flowDir: string) {
this.watchFlowFiles();
}
private watchFlowFiles() {
this.watcher = fs.watch(this.flowDir, (event, filename) => {
if (filename.endsWith('.js')) {
this.loadFlow(path.join(this.flowDir, filename));
}
});
}
private async loadFlow(filepath: string) {
const flowName = path.basename(filepath, '.js');
delete require.cache[require.resolve(filepath)];
const flow = require(filepath);
this.flows.set(flowName, flow);
}
getFlow(name: string) {
return this.flows.get(name);
}
}
15.3 蓝绿部署策略
typescript复制class FlowDeployer {
constructor(private production: FlowManager,
private staging: FlowManager) {}
async deploy(newFlow: Flow) {
// 部署到预发布环境
await this.staging.register(newFlow);
// 验证流程
const testResult = await this.validateFlow(newFlow);
if (!testResult.success) {
throw new Error('Flow validation failed');
}
// 切换到新流程
await this.production.register(newFlow);
// 保留旧流程一段时间
setTimeout(() => {
this.staging.cleanup();
}, 24 * 60 * 60 * 1000);
}
}
16. 未来演进方向
16.1 机器学习优化
通过分析历史执行数据,自动优化流程:
typescript复制class FlowOptimizer {
constructor(private historyRepo: ExecutionHistoryRepository) {}
async optimize(flow: Flow) {
const history = await this.historyRepo.getSimilarFlows(flow);
const analysis = this.analyzeHistory(history
