UNPKG

autotel

Version:
226 lines (222 loc) 7.37 kB
import { Attributes, SpanContext } from '@opentelemetry/api'; import { T as TraceContext } from './trace-context-t5X1AP-e.js'; /** * Workflow and Saga tracing helpers * * Provides specialized tracing for multi-step workflows and sagas with * automatic step linking, compensation tracking, and workflow correlation. * * @example Simple workflow * ```typescript * import { traceWorkflow, traceStep } from 'autotel/workflow'; * * export const processOrder = traceWorkflow({ * name: 'OrderFulfillment', * workflowId: (order) => order.id, * })(ctx => async (order: Order) => { * await validateOrder(order); * await chargePayment(order); * await shipOrder(order); * }); * ``` * * @example Saga with compensation * ```typescript * import { traceWorkflow, traceStep } from 'autotel/workflow'; * * export const orderSaga = traceWorkflow({ * name: 'OrderSaga', * workflowId: () => generateUUID(), * })(ctx => async (order: Order) => { * * const reserveStep = traceStep({ * name: 'ReserveInventory', * compensate: async () => { * await releaseInventory(order.items); * }, * })(async () => { * await inventoryService.reserve(order.items); * }); * await reserveStep(); * * const paymentStep = traceStep({ * name: 'ProcessPayment', * linkToPrevious: true, * compensate: async () => { * await refundPayment(order.paymentId); * }, * })(async () => { * await paymentService.charge(order); * }); * await paymentStep(); * }); * ``` * * @module */ /** * Workflow status */ type WorkflowStatus = 'pending' | 'running' | 'completed' | 'failed' | 'compensating' | 'compensated' | 'compensation_failed'; /** * Step status */ type StepStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped' | 'compensated'; /** * Configuration for workflow tracing */ interface WorkflowConfig<TArgs extends unknown[] = unknown[]> { /** Workflow name (e.g., 'OrderFulfillment', 'UserOnboarding') */ name: string; /** * Function to extract or generate workflow ID * Can be static string, function of args, or generator */ workflowId: string | ((...args: TArgs) => string); /** Optional workflow version */ version?: string; /** Additional attributes */ attributes?: Attributes; /** Callback on workflow completion */ onComplete?: (ctx: WorkflowContext, result: unknown) => void; /** Callback on workflow failure */ onFailed?: (ctx: WorkflowContext, error: Error) => void; /** Callback on compensation start */ onCompensating?: (ctx: WorkflowContext) => void; } /** * Configuration for workflow step tracing */ interface StepConfig { /** Step name */ name: string; /** Optional step description */ description?: string; /** Step index (auto-assigned if not provided) */ index?: number; /** Link to previous step span */ linkToPrevious?: boolean; /** Link to specific step(s) by name */ linkTo?: string | string[]; /** Additional attributes */ attributes?: Attributes; /** Compensation handler for saga rollback */ compensate?: (error: Error) => Promise<void> | void; /** Whether this step is idempotent */ idempotent?: boolean; /** Retry configuration */ retry?: { maxAttempts: number; backoffMs?: number; }; /** Callback on step completion */ onComplete?: (ctx: StepContext) => void; /** Callback on step failure */ onFailed?: (ctx: StepContext, error: Error) => void; } /** * Extended trace context for workflows */ interface WorkflowContext extends TraceContext { /** Get the workflow ID */ getWorkflowId(): string; /** Get workflow name */ getWorkflowName(): string; /** Get current workflow status */ getStatus(): WorkflowStatus; /** Mark step as completed and store for linking */ completeStep(stepName: string): void; /** Get previous step's span context for linking */ getPreviousStep(stepName?: string): SpanContext | null; /** Get all completed steps */ getCompletedSteps(): string[]; /** Register a compensation handler */ registerCompensation(stepName: string, handler: (error: Error) => Promise<void> | void): void; /** Trigger compensation for all registered steps */ compensate(error: Error): Promise<void>; /** Record compensation result */ recordCompensation(stepName: string, success: boolean, error?: Error): void; /** Set workflow status */ setWorkflowStatus(status: WorkflowStatus): void; } /** * Extended trace context for workflow steps */ interface StepContext extends TraceContext { /** Get step name */ getStepName(): string; /** Get step index */ getStepIndex(): number; /** Mark this step as completed */ complete(): void; /** Skip this step */ skip(reason?: string): void; /** Get workflow context */ getWorkflowContext(): WorkflowContext | null; } /** * Create a traced workflow function * * Wraps business logic in a workflow span with automatic step tracking, * correlation via workflow ID, and compensation support. * * @param config - Workflow configuration * @returns Factory function that wraps your workflow logic * * @example Order fulfillment workflow * ```typescript * export const fulfillOrder = traceWorkflow({ * name: 'OrderFulfillment', * workflowId: (order) => order.id, * version: '2.0', * })(ctx => async (order: Order) => { * ctx.setAttribute('order.total', order.total); * * await validateOrder(order); * await processPayment(order); * await fulfillItems(order); * await notifyCustomer(order); * * return { success: true, orderId: order.id }; * }); * ``` */ declare function traceWorkflow<TArgs extends unknown[], TReturn>(config: WorkflowConfig<TArgs>): (fnFactory: (ctx: WorkflowContext) => (...args: TArgs) => Promise<TReturn>) => ((...args: TArgs) => Promise<TReturn>); /** * Create a traced workflow step * * Wraps step logic with automatic linking to previous steps, * compensation registration, and status tracking. * * @param config - Step configuration * @returns Factory function that wraps your step logic * * @example Step with compensation * ```typescript * const chargePayment = traceStep({ * name: 'ChargePayment', * linkToPrevious: true, * compensate: async (error) => { * await paymentService.refund(paymentId); * }, * })(async (amount: number) => { * return await paymentService.charge(amount); * }); * ``` */ declare function traceStep<TArgs extends unknown[], TReturn>(config: StepConfig): (fn: (...args: TArgs) => Promise<TReturn>) => ((...args: TArgs) => Promise<TReturn>); /** * Get current workflow context (if inside a workflow) * * Uses AsyncLocalStorage to ensure async-safety when multiple * workflows are running concurrently. */ declare function getCurrentWorkflowContext(): WorkflowContext | null; /** * Check if currently executing inside a workflow * * Uses AsyncLocalStorage to ensure async-safety when multiple * workflows are running concurrently. */ declare function isInWorkflow(): boolean; export { type StepConfig, type StepContext, type StepStatus, type WorkflowConfig, type WorkflowContext, type WorkflowStatus, getCurrentWorkflowContext, isInWorkflow, traceStep, traceWorkflow };