UNPKG

autotel

Version:
344 lines (341 loc) 11.2 kB
'use strict'; var chunk4P6ZOARG_cjs = require('./chunk-4P6ZOARG.cjs'); var chunkTY4NXDYR_cjs = require('./chunk-TY4NXDYR.cjs'); var chunkNCSMD3TK_cjs = require('./chunk-NCSMD3TK.cjs'); var async_hooks = require('async_hooks'); var workflowStates = /* @__PURE__ */ new WeakMap(); var workflowContextStorage = new async_hooks.AsyncLocalStorage(); function traceWorkflow(config) { const spanName = `workflow.${config.name}`; return (fnFactory) => { return chunkTY4NXDYR_cjs.trace(spanName, (baseCtx) => { return async (...args) => { const workflowId = typeof config.workflowId === "function" ? config.workflowId(...args) : config.workflowId; const ctx = createWorkflowContext(baseCtx, config.name, workflowId); ctx.setAttribute("workflow.name", config.name); ctx.setAttribute("workflow.id", workflowId); if (config.version) { ctx.setAttribute("workflow.version", config.version); } ctx.setAttribute("workflow.status", "running"); if (config.attributes) { for (const [key, value] of Object.entries(config.attributes)) { if (value !== void 0) { ctx.setAttribute(key, value); } } } return workflowContextStorage.run(ctx, async () => { try { const userFn = fnFactory(ctx); const result = await userFn(...args); ctx.setWorkflowStatus("completed"); config.onComplete?.(ctx, result); return result; } catch (error) { ctx.setWorkflowStatus("failed"); config.onFailed?.(ctx, error); const state = getWorkflowState(); if (state && state.compensations.size > 0) { ctx.setWorkflowStatus("compensating"); config.onCompensating?.(ctx); try { await ctx.compensate(error); ctx.setWorkflowStatus("compensated"); } catch (compensationError) { ctx.setWorkflowStatus("compensation_failed"); ctx.setAttribute( "workflow.compensation.error", String(compensationError) ); } } throw error; } }); }; }); }; } function traceStep(config) { return (fn) => { const spanName = `step.${config.name}`; return chunkTY4NXDYR_cjs.trace(spanName, (baseCtx) => { return async (...args) => { const workflowCtx = workflowContextStorage.getStore() ?? null; const ctx = createStepContext(baseCtx, config, workflowCtx); ctx.setAttribute("workflow.step.name", config.name); ctx.setAttribute("workflow.step.index", ctx.getStepIndex()); ctx.setAttribute("workflow.step.status", "running"); if (config.description) { ctx.setAttribute("workflow.step.description", config.description); } if (config.idempotent) { ctx.setAttribute("workflow.step.idempotent", true); } if (config.attributes) { for (const [key, value] of Object.entries(config.attributes)) { if (value !== void 0) { ctx.setAttribute(key, value); } } } await addStepLinks(ctx, config, workflowCtx); if (config.compensate && workflowCtx) { workflowCtx.registerCompensation(config.name, config.compensate); } let lastError; const maxAttempts = config.retry?.maxAttempts ?? 1; for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { if (attempt > 1) { ctx.setAttribute("workflow.step.retry_attempt", attempt); chunk4P6ZOARG_cjs.emitCorrelatedEvent(ctx, "step_retry", { "workflow.step.attempt": attempt, "workflow.step.max_attempts": maxAttempts }); if (config.retry?.backoffMs) { await sleep(config.retry.backoffMs * attempt); } } const result = await fn(...args); ctx.setAttribute("workflow.step.status", "completed"); ctx.complete(); config.onComplete?.(ctx); return result; } catch (error) { lastError = error; if (attempt < maxAttempts) { chunk4P6ZOARG_cjs.emitCorrelatedEvent(ctx, "step_retry_scheduled", { "workflow.step.error": String(error), "workflow.step.attempt": attempt }); } } } ctx.setAttribute("workflow.step.status", "failed"); ctx.setAttribute("workflow.step.error", String(lastError)); config.onFailed?.(ctx, lastError); throw lastError; }; }); }; } function createWorkflowContext(baseCtx, workflowName, workflowId) { const span = chunkNCSMD3TK_cjs.getActiveSpan(); const state = { workflowId, workflowName, status: "running", steps: /* @__PURE__ */ new Map(), stepCounter: 0, compensations: /* @__PURE__ */ new Map() }; if (span) { workflowStates.set(span, state); } return { ...baseCtx, getWorkflowId() { return workflowId; }, getWorkflowName() { return workflowName; }, getStatus() { return state.status; }, completeStep(stepName) { let step = state.steps.get(stepName); if (!step) { step = { name: stepName, index: state.stepCounter++, status: "pending", startTime: Date.now() }; state.steps.set(stepName, step); } step.status = "completed"; step.endTime = Date.now(); const currentSpan = chunkNCSMD3TK_cjs.getActiveSpan(); if (currentSpan) { step.spanContext = currentSpan.spanContext(); } }, getPreviousStep(stepName) { if (stepName) { const step = state.steps.get(stepName); return step?.spanContext ?? null; } let lastStep = null; for (const step of state.steps.values()) { if (step.status === "completed" && (!lastStep || step.index > lastStep.index)) { lastStep = step; } } return lastStep?.spanContext ?? null; }, getCompletedSteps() { const completed = []; for (const [name, step] of state.steps) { if (step.status === "completed") { completed.push(name); } } return completed.toSorted( (a, b) => (state.steps.get(a)?.index ?? 0) - (state.steps.get(b)?.index ?? 0) ); }, registerCompensation(stepName, handler) { state.compensations.set(stepName, handler); }, async compensate(error) { const compensationOrder = [...state.compensations.entries()].toReversed(); for (const [stepName, handler] of compensationOrder) { const step = state.steps.get(stepName); if (step && step.status === "completed") { try { chunk4P6ZOARG_cjs.emitCorrelatedEvent(baseCtx, "compensation_started", { "workflow.step.name": stepName }); await Promise.resolve(handler(error)); this.recordCompensation(stepName, true); step.status = "compensated"; } catch (compensationError) { this.recordCompensation( stepName, false, compensationError ); throw compensationError; } } } }, recordCompensation(stepName, success, error) { chunk4P6ZOARG_cjs.emitCorrelatedEvent(baseCtx, "compensation_completed", { "workflow.step.name": stepName, "workflow.compensation.success": success, ...error && { "workflow.compensation.error": String(error) } }); baseCtx.setAttribute( `workflow.compensation.${stepName}`, success ? "success" : "failed" ); }, setWorkflowStatus(status) { state.status = status; baseCtx.setAttribute("workflow.status", status); chunk4P6ZOARG_cjs.emitCorrelatedEvent(baseCtx, "workflow_status_changed", { "workflow.status": status }); } }; } function createStepContext(baseCtx, config, workflowCtx) { let stepIndex = config.index ?? 0; if (workflowCtx) { const span = chunkNCSMD3TK_cjs.getActiveSpan(); if (span) { const state = workflowStates.get(span); if (state) { stepIndex = config.index ?? state.stepCounter++; } } } if (workflowCtx) { const wfSpan = chunkNCSMD3TK_cjs.getActiveSpan(); if (wfSpan) { const state = workflowStates.get(wfSpan); if (state) { state.steps.set(config.name, { name: config.name, index: stepIndex, status: "running", startTime: Date.now(), compensate: config.compensate }); } } } return { ...baseCtx, getStepName() { return config.name; }, getStepIndex() { return stepIndex; }, complete() { if (workflowCtx) { workflowCtx.completeStep(config.name); } }, skip(reason) { baseCtx.setAttribute("workflow.step.status", "skipped"); if (reason) { baseCtx.setAttribute("workflow.step.skip_reason", reason); } chunk4P6ZOARG_cjs.emitCorrelatedEvent(baseCtx, "step_skipped", { "workflow.step.name": config.name, ...reason && { "workflow.step.skip_reason": reason } }); }, getWorkflowContext() { return workflowCtx; } }; } function getWorkflowState() { const span = chunkNCSMD3TK_cjs.getActiveSpan(); return span ? workflowStates.get(span) : null; } async function addStepLinks(ctx, config, workflowCtx) { if (!workflowCtx) return; const links = []; if (config.linkToPrevious) { const prevSpanContext = workflowCtx.getPreviousStep(); if (prevSpanContext) { links.push({ context: prevSpanContext, attributes: { "workflow.link.type": "sequence" } }); } } if (config.linkTo) { const stepNames = Array.isArray(config.linkTo) ? config.linkTo : [config.linkTo]; for (const stepName of stepNames) { const spanContext = workflowCtx.getPreviousStep(stepName); if (spanContext) { links.push({ context: spanContext, attributes: { "workflow.link.type": "dependency", "workflow.link.step": stepName } }); } } } if (links.length > 0) { ctx.addLinks(links); } } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } function getCurrentWorkflowContext() { return workflowContextStorage.getStore() ?? null; } function isInWorkflow() { return workflowContextStorage.getStore() !== void 0; } exports.getCurrentWorkflowContext = getCurrentWorkflowContext; exports.isInWorkflow = isInWorkflow; exports.traceStep = traceStep; exports.traceWorkflow = traceWorkflow; //# sourceMappingURL=chunk-K4UDKM3P.cjs.map //# sourceMappingURL=chunk-K4UDKM3P.cjs.map