UNPKG

smart-saga-pattern

Version:

A library implementing the Saga pattern for microservice architecture

149 lines (148 loc) 5.84 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SagaCoordinator = void 0; const Saga_1 = require("../core/Saga"); const types_1 = require("../types"); /** * Coordinates a choreography-based Saga */ class SagaCoordinator extends Saga_1.Saga { /** * Creates a new SagaCoordinator * @param participant Saga participant for communication * @param options Options for the coordinator * @param stateStore Optional state store for persistence */ constructor(participant, options, stateStore) { super(options); this.participant = participant; this.stateStore = stateStore; // Set up event handlers this.setupEventHandlers(); } /** * Executes the Saga * @param initialData Initial data for the Saga */ async execute(initialData) { try { // Update context with initial data if (initialData) { this.updateContext(initialData); } // Save initial state if state store is provided if (this.stateStore) { await this.stateStore.save(this.getId(), this.getContext()); } // Set up completion promise this.completionPromise = new Promise((resolve, reject) => { this.completionResolve = resolve; this.completionReject = reject; }); // Start the Saga by publishing the initial event await this.participant.publish('SAGA_STARTED', this.context.data, this.getId()); // Set status to executing this.setStatus(types_1.SagaStatus.EXECUTING); // Update state store if provided if (this.stateStore) { await this.stateStore.update(this.getId(), this.context); } // Wait for completion return await this.completionPromise; } catch (error) { this.setStatus(types_1.SagaStatus.FAILED, error instanceof Error ? error.message : String(error)); // Update state store if provided if (this.stateStore) { await this.stateStore.update(this.getId(), this.context); } return this.getContext(); } } /** * Compensates the Saga (rolls back) */ async compensate() { try { this.setStatus(types_1.SagaStatus.COMPENSATING); // Update state store if provided if (this.stateStore) { await this.stateStore.update(this.getId(), this.context); } // Publish compensation event await this.participant.publish('SAGA_COMPENSATE', this.context.data, this.getId()); // Wait for completion return await this.completionPromise; } catch (error) { this.setStatus(types_1.SagaStatus.COMPENSATION_FAILED, error instanceof Error ? error.message : String(error)); // Update state store if provided if (this.stateStore) { await this.stateStore.update(this.getId(), this.context); } return this.getContext(); } } /** * Sets up event handlers for the coordinator */ setupEventHandlers() { // Handle saga completion this.participant.on('SAGA_COMPLETED', async (event) => { this.setStatus(types_1.SagaStatus.COMPLETED); // Update context with event payload this.updateContext(event.payload); // Update state store if provided if (this.stateStore) { await this.stateStore.update(this.getId(), this.context); } // Resolve completion promise if (this.completionResolve) { this.completionResolve(this.getContext()); } }); // Handle saga failure this.participant.on('SAGA_FAILED', async (event) => { this.setStatus(types_1.SagaStatus.FAILED, event.payload.error); // Update context with event payload this.updateContext(event.payload); // Update state store if provided if (this.stateStore) { await this.stateStore.update(this.getId(), this.context); } // Reject completion promise if (this.completionReject) { this.completionReject(new Error(event.payload.error)); } }); // Handle saga compensation completed this.participant.on('SAGA_COMPENSATED', async (event) => { this.setStatus(types_1.SagaStatus.COMPENSATED); // Update context with event payload this.updateContext(event.payload); // Update state store if provided if (this.stateStore) { await this.stateStore.update(this.getId(), this.context); } // Resolve completion promise if (this.completionResolve) { this.completionResolve(this.getContext()); } }); // Handle saga compensation failed this.participant.on('SAGA_COMPENSATION_FAILED', async (event) => { this.setStatus(types_1.SagaStatus.COMPENSATION_FAILED, event.payload.error); // Update context with event payload this.updateContext(event.payload); // Update state store if provided if (this.stateStore) { await this.stateStore.update(this.getId(), this.context); } // Reject completion promise if (this.completionReject) { this.completionReject(new Error(event.payload.error)); } }); } } exports.SagaCoordinator = SagaCoordinator;