execution-engine
Version:
A TypeScript library for tracing and visualizing code execution workflows.
80 lines (79 loc) • 3.45 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.executionTrace = executionTrace;
const execute_1 = require("./execute");
const functionMetadata_1 = require("../common/utils/functionMetadata");
const safeError_1 = require("../common/utils/safeError");
const executionTimer_1 = require("../timer/executionTimer");
function calculateTimeAndDuration(executionTimer) {
executionTimer.stop();
const timerDetails = executionTimer.getInfo(undefined, undefined, 3);
delete timerDetails.executionId;
return timerDetails;
}
/**
* Executes a given function (`blockFunction`) while tracing its execution details, including inputs, outputs,
* timing, metadata, and potential errors. Supports both synchronous and asynchronous functions.
*
* @template O - The return type of `blockFunction`, which can be synchronous (`O`) or a `Promise<O>`.
*
* @param blockFunction - The function to execute and trace.
* @param inputs - An array of input parameters to pass to `blockFunction`. Defaults to an empty array.
* @param onTraceEvent - An optional callback function that processes the trace context after execution.
* @param options - Optional configuration:
* - `contextKey`: A key to store and retrieve execution context.
* - `errorStrategy`: Determines how errors are handled:
* - `'catch'`: Captures errors and includes them in the trace.
* - `'throw'`: Throws the error after recording it in the trace.
*
* @returns An Either:
* - `ExecutionTrace` object containing execution details.
* - If `blockFunction` is asynchronous, returns a `Promise<ExecutionTrace>`.
*/
function executionTrace(blockFunction, inputs = [], onTraceEvent, options = {
contextKey: undefined,
errorStrategy: 'throw'
}) {
const id = crypto.randomUUID();
const executionTimer = new executionTimer_1.ExecutionTimer(id);
executionTimer?.start();
const executionTrace = { id, inputs, startTime: executionTimer.getStartDate() };
const functionMetadata = (0, functionMetadata_1.extractFunctionMetadata)(blockFunction);
let traceContext = { metadata: functionMetadata, ...executionTrace };
if (this && options.contextKey) {
traceContext = { ...traceContext, ...this[options.contextKey] };
this[options.contextKey] = traceContext;
}
return execute_1.execute.bind(this)(blockFunction.bind(this), inputs, [traceContext], function (outputs, isPromise) {
const { startTime, ...traceContextWithoutStartTime } = traceContext;
traceContext = {
...traceContextWithoutStartTime,
outputs,
isPromise,
startTime,
...calculateTimeAndDuration(executionTimer)
};
if (typeof onTraceEvent === 'function') {
onTraceEvent(traceContext);
}
return traceContext;
}, function (e, isPromise) {
const { startTime, ...traceContextWithoutStartTime } = traceContext;
traceContext = {
...traceContextWithoutStartTime,
errors: [(0, safeError_1.safeError)(e)],
isPromise,
startTime,
...calculateTimeAndDuration(executionTimer)
};
if (typeof onTraceEvent === 'function') {
onTraceEvent(traceContext);
}
if (options?.errorStrategy === 'catch') {
return traceContext;
}
else {
throw e;
}
});
}
;