autotel
Version:
Write Once, Observe Anywhere
426 lines (424 loc) • 14.9 kB
JavaScript
import { createSafeBaggageSchema } from './chunk-4IFSYQVX.js';
import { trace } from './chunk-HPUGKUMZ.js';
import './chunk-B3ZHLLMP.js';
import './chunk-WD4RP6IV.js';
import './chunk-S4OFEXLA.js';
import './chunk-BBBWDIYQ.js';
import './chunk-W35FVJBC.js';
import './chunk-3SDILILG.js';
import './chunk-A4E5AQFK.js';
import './chunk-WGWSHJ2N.js';
import './chunk-GYR5K654.js';
import './chunk-TDNKIHKT.js';
import './chunk-6UQRVUN3.js';
import './chunk-3QXBFGKP.js';
import './chunk-33WTKH7X.js';
import './chunk-DPSA4QLA.js';
import './chunk-55ER2KD5.js';
import './chunk-J5QENANM.js';
import './chunk-HA2WBOGQ.js';
import './chunk-DGUM43GV.js';
import { SpanKind, context, propagation } from '@opentelemetry/api';
var workflowBaggageFields = {
/** Unique identifier for the workflow instance */
workflowId: { type: "string", maxLength: 128, required: true },
/** Name/type of the workflow (e.g., "OrderFulfillment") */
workflowName: { type: "string", maxLength: 64, required: true },
/** Version of the workflow definition */
workflowVersion: { type: "string", maxLength: 32 },
/** Current step name */
stepName: { type: "string", maxLength: 64 },
/** Current step index (0-based) */
stepIndex: { type: "number" },
/** Total number of steps (if known) */
totalSteps: { type: "number" },
/** Parent workflow ID (for sub-workflows) */
parentWorkflowId: { type: "string", maxLength: 128 },
/** Correlation ID for external systems */
correlationId: { type: "string", maxLength: 128 },
/** Workflow priority */
priority: {
type: "enum",
values: ["low", "normal", "high", "critical"]
},
/** Initiating user/system */
initiatedBy: { type: "string", maxLength: 64 },
/** Workflow start timestamp (ISO) */
startedAt: { type: "string", maxLength: 30 }
};
var WorkflowBaggage = createSafeBaggageSchema(workflowBaggageFields, {
prefix: "workflow",
hashHighCardinality: false,
// Workflow IDs should be traceable
redactPII: false
// Workflow fields are internal identifiers
});
function traceDistributedWorkflow(config) {
const spanName = `workflow.${config.name}`;
return (fnFactory) => {
return trace(
{ name: spanName, spanKind: SpanKind.INTERNAL },
(baseCtx) => {
return async (...args) => {
const workflowId = config.workflowIdFrom(...args);
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
const baggageValues = {
workflowId,
workflowName: config.name,
workflowVersion: config.version,
stepIndex: 0,
totalSteps: config.totalSteps,
parentWorkflowId: config.parentWorkflowId,
correlationId: config.correlationId,
priority: config.priority,
initiatedBy: config.initiatedBy,
startedAt
};
WorkflowBaggage.set(baseCtx, baggageValues);
baseCtx.setAttribute("workflow.id", workflowId);
baseCtx.setAttribute("workflow.name", config.name);
if (config.version) {
baseCtx.setAttribute("workflow.version", config.version);
}
if (config.totalSteps) {
baseCtx.setAttribute("workflow.total_steps", config.totalSteps);
}
if (config.parentWorkflowId) {
baseCtx.setAttribute("workflow.parent_id", config.parentWorkflowId);
}
if (config.priority) {
baseCtx.setAttribute("workflow.priority", config.priority);
}
if (config.initiatedBy) {
baseCtx.setAttribute("workflow.initiated_by", config.initiatedBy);
}
baseCtx.setAttribute("workflow.started_at", startedAt);
if (config.attributes) {
for (const [key, value] of Object.entries(config.attributes)) {
baseCtx.setAttribute(key, value);
}
}
const workflowCtx = {
...baseCtx,
workflowId,
workflowName: config.name,
workflowVersion: config.version,
getWorkflowBaggage() {
return { ...baggageValues };
},
setWorkflowBaggage(values) {
Object.assign(baggageValues, values);
WorkflowBaggage.set(baseCtx, baggageValues);
},
getWorkflowHeaders() {
const headers = {};
const ctx = context.active();
propagation.inject(ctx, headers);
return headers;
},
recordStepProgress(stepName, stepIndex) {
baggageValues.stepName = stepName;
baggageValues.stepIndex = stepIndex;
WorkflowBaggage.set(baseCtx, baggageValues);
baseCtx.addEvent("workflow.step_progress", {
"workflow.step.name": stepName,
"workflow.step.index": stepIndex
});
}
};
config.onStart?.(workflowCtx);
baseCtx.addEvent("workflow.started", {
"workflow.id": workflowId,
"workflow.name": config.name
});
try {
const userFn = fnFactory(workflowCtx);
const result = await userFn(...args);
config.onComplete?.(workflowCtx, result);
baseCtx.addEvent("workflow.completed", {
"workflow.id": workflowId
});
return result;
} catch (error) {
config.onError?.(workflowCtx, error);
baseCtx.addEvent("workflow.failed", {
"workflow.id": workflowId,
"workflow.error": error.message
});
throw error;
}
};
}
);
};
}
function traceDistributedStep(config) {
const spanName = `workflow.step.${config.name}`;
return (fnFactory) => {
return trace(
{ name: spanName, spanKind: SpanKind.INTERNAL },
(baseCtx) => {
return async (...args) => {
let baggageValues = null;
const extractBaggage = config.extractBaggage ?? true;
if (typeof extractBaggage === "function") {
baggageValues = extractBaggage(args);
} else if (extractBaggage) {
const extracted = WorkflowBaggage.get(baseCtx);
if (extracted.workflowId && extracted.workflowName) {
baggageValues = extracted;
}
}
let stepIndex;
if (config.stepIndex !== void 0) {
stepIndex = config.stepIndex;
} else if (baggageValues?.stepIndex === void 0) {
stepIndex = null;
} else {
stepIndex = baggageValues.stepIndex + 1;
}
if (baggageValues) {
baggageValues.stepName = config.name;
if (stepIndex !== null) {
baggageValues.stepIndex = stepIndex;
}
WorkflowBaggage.set(baseCtx, baggageValues);
}
baseCtx.setAttribute("workflow.step.name", config.name);
if (stepIndex !== null) {
baseCtx.setAttribute("workflow.step.index", stepIndex);
}
if (config.idempotent !== void 0) {
baseCtx.setAttribute("workflow.step.idempotent", config.idempotent);
}
if (config.isCompensation) {
baseCtx.setAttribute("workflow.step.is_compensation", true);
}
if (baggageValues) {
baseCtx.setAttribute("workflow.id", baggageValues.workflowId);
baseCtx.setAttribute("workflow.name", baggageValues.workflowName);
if (baggageValues.workflowVersion) {
baseCtx.setAttribute(
"workflow.version",
baggageValues.workflowVersion
);
}
if (baggageValues.totalSteps) {
baseCtx.setAttribute(
"workflow.total_steps",
baggageValues.totalSteps
);
}
}
if (config.attributes) {
for (const [key, value] of Object.entries(config.attributes)) {
baseCtx.setAttribute(key, value);
}
}
let compensationData;
const stepCtx = {
...baseCtx,
workflowId: baggageValues?.workflowId ?? null,
workflowName: baggageValues?.workflowName ?? null,
stepName: config.name,
stepIndex,
isCompensation: config.isCompensation ?? false,
getWorkflowBaggage() {
return baggageValues ? { ...baggageValues } : null;
},
updateWorkflowBaggage(values) {
if (baggageValues) {
Object.assign(baggageValues, values);
WorkflowBaggage.set(baseCtx, baggageValues);
}
},
getWorkflowHeaders() {
const headers = {};
const ctx = context.active();
propagation.inject(ctx, headers);
return headers;
},
requiresCompensation(data) {
compensationData = data;
baseCtx.setAttribute("workflow.step.requires_compensation", true);
baseCtx.addEvent("workflow.step.compensation_registered", {
"workflow.step.name": config.name,
...data && {
"workflow.step.compensation_data": JSON.stringify(data)
}
});
}
};
config.onStart?.(stepCtx);
baseCtx.addEvent("workflow.step.started", {
"workflow.step.name": config.name,
...baggageValues && { "workflow.id": baggageValues.workflowId }
});
try {
const userFn = fnFactory(stepCtx);
const result = await userFn(...args);
config.onComplete?.(stepCtx, result);
baseCtx.addEvent("workflow.step.completed", {
"workflow.step.name": config.name
});
return result;
} catch (error) {
config.onError?.(stepCtx, error);
baseCtx.addEvent("workflow.step.failed", {
"workflow.step.name": config.name,
"workflow.step.error": error.message,
...compensationData && {
"workflow.step.requires_compensation": true
}
});
throw error;
}
};
}
);
};
}
function generateWorkflowId(prefix) {
const random = Math.random().toString(36).slice(2, 15);
const timestamp = Date.now().toString(36);
const id = `${timestamp}-${random}`;
return prefix ? `${prefix}-${id}` : id;
}
function isInDistributedWorkflow(ctx) {
const baggage = WorkflowBaggage.get(ctx);
return !!(baggage.workflowId && baggage.workflowName);
}
function getWorkflowProgress(ctx) {
const baggage = WorkflowBaggage.get(ctx);
if (!baggage.workflowId || !baggage.workflowName) {
return null;
}
const percentComplete = baggage.totalSteps && baggage.stepIndex !== void 0 ? Math.round((baggage.stepIndex + 1) / baggage.totalSteps * 100) : null;
return {
workflowId: baggage.workflowId,
workflowName: baggage.workflowName,
currentStep: baggage.stepName ?? null,
currentStepIndex: baggage.stepIndex ?? null,
totalSteps: baggage.totalSteps ?? null,
percentComplete
};
}
function createWorkflowHeaders(values) {
const headers = {};
const baggageEntries = [];
if (values.workflowId) {
baggageEntries.push(
`workflow.workflowId=${encodeURIComponent(values.workflowId)}`
);
}
if (values.workflowName) {
baggageEntries.push(
`workflow.workflowName=${encodeURIComponent(values.workflowName)}`
);
}
if (values.workflowVersion) {
baggageEntries.push(
`workflow.workflowVersion=${encodeURIComponent(values.workflowVersion)}`
);
}
if (values.stepName) {
baggageEntries.push(
`workflow.stepName=${encodeURIComponent(values.stepName)}`
);
}
if (values.stepIndex !== void 0) {
baggageEntries.push(`workflow.stepIndex=${values.stepIndex}`);
}
if (values.totalSteps !== void 0) {
baggageEntries.push(`workflow.totalSteps=${values.totalSteps}`);
}
if (values.priority) {
baggageEntries.push(`workflow.priority=${values.priority}`);
}
if (values.correlationId) {
baggageEntries.push(
`workflow.correlationId=${encodeURIComponent(values.correlationId)}`
);
}
if (values.parentWorkflowId) {
baggageEntries.push(
`workflow.parentWorkflowId=${encodeURIComponent(values.parentWorkflowId)}`
);
}
if (values.initiatedBy) {
baggageEntries.push(
`workflow.initiatedBy=${encodeURIComponent(values.initiatedBy)}`
);
}
if (values.startedAt) {
baggageEntries.push(
`workflow.startedAt=${encodeURIComponent(values.startedAt)}`
);
}
if (baggageEntries.length > 0) {
headers["baggage"] = baggageEntries.join(",");
}
return headers;
}
function parseWorkflowFromBaggage(baggageHeader) {
if (!baggageHeader) {
return null;
}
const values = {};
const entries = baggageHeader.split(",");
for (const entry of entries) {
const [key, value] = entry.trim().split("=");
if (!key || !value) continue;
const decodedValue = decodeURIComponent(value);
switch (key) {
case "workflow.workflowId": {
values.workflowId = decodedValue;
break;
}
case "workflow.workflowName": {
values.workflowName = decodedValue;
break;
}
case "workflow.workflowVersion": {
values.workflowVersion = decodedValue;
break;
}
case "workflow.stepName": {
values.stepName = decodedValue;
break;
}
case "workflow.stepIndex": {
values.stepIndex = Number.parseInt(decodedValue, 10);
break;
}
case "workflow.totalSteps": {
values.totalSteps = Number.parseInt(decodedValue, 10);
break;
}
case "workflow.priority": {
values.priority = decodedValue;
break;
}
case "workflow.correlationId": {
values.correlationId = decodedValue;
break;
}
case "workflow.parentWorkflowId": {
values.parentWorkflowId = decodedValue;
break;
}
case "workflow.initiatedBy": {
values.initiatedBy = decodedValue;
break;
}
case "workflow.startedAt": {
values.startedAt = decodedValue;
break;
}
}
}
return Object.keys(values).length > 0 ? values : null;
}
export { WorkflowBaggage, createWorkflowHeaders, generateWorkflowId, getWorkflowProgress, isInDistributedWorkflow, parseWorkflowFromBaggage, traceDistributedStep, traceDistributedWorkflow };
//# sourceMappingURL=workflow-distributed.js.map
//# sourceMappingURL=workflow-distributed.js.map