UNPKG

smart-saga-pattern

Version:

A library implementing the Saga pattern for microservice architecture

102 lines (101 loc) 4.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SagaExecutor = void 0; const types_1 = require("../types"); /** * Executes a Saga definition * @template T Type of the input data * @template R Type of the result data */ class SagaExecutor { /** * Creates a new SagaExecutor * @param definition Saga definition to execute * @param context Initial Saga context */ constructor(definition, context) { this.currentStepIndex = -1; this.definition = definition; this.context = { ...context }; } /** * Executes the Saga */ async execute() { const steps = this.definition.getSteps(); try { this.context.status = types_1.SagaStatus.EXECUTING; for (let i = 0; i < steps.length; i++) { this.currentStepIndex = i; const step = steps[i]; try { // Execute the transaction with the requiresCompensation flag const requiresCompensation = step.requiresCompensation !== undefined ? step.requiresCompensation : true; const result = await step.transaction.execute(this.context.data, requiresCompensation); // Update context with the result using the step name as the key this.context.data = { ...this.context.data, [step.transaction.getName()]: result, }; } catch (error) { // Transaction failed, start compensation await this.compensate(); return this.context; } } // All steps completed successfully this.context.status = types_1.SagaStatus.COMPLETED; this.context.endTime = Date.now(); return this.context; } catch (error) { // Something went wrong during execution or compensation this.context.status = types_1.SagaStatus.FAILED; this.context.error = error instanceof Error ? error.message : String(error); this.context.endTime = Date.now(); return this.context; } } /** * Compensates the Saga */ async compensate() { const steps = this.definition.getSteps(); this.context.status = types_1.SagaStatus.COMPENSATING; try { // Compensate steps in reverse order for (let i = this.currentStepIndex; i >= 0; i--) { const step = steps[i]; // Only compensate if the step requires compensation if (step.compensation && step.requiresCompensation !== false) { try { // Get the transaction result from the context const transactionResult = this.context.data[step.transaction.getName()]; // Execute compensation with transaction result and name await step.compensation.execute(this.context.data, transactionResult, step.transaction.getName()); } catch (error) { // Compensation failed this.context.status = types_1.SagaStatus.COMPENSATION_FAILED; this.context.error = error instanceof Error ? error.message : String(error); this.context.endTime = Date.now(); throw error; } } } // All compensations completed successfully this.context.status = types_1.SagaStatus.COMPENSATED; this.context.endTime = Date.now(); } catch (error) { // Re-throw the error to be caught by the execute method throw error; } } } exports.SagaExecutor = SagaExecutor;