smart-saga-pattern
Version:
A library implementing the Saga pattern for microservice architecture
130 lines (129 loc) • 4.58 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StructuredSagaOrchestrator = void 0;
const Saga_1 = require("../core/Saga");
const StructuredSagaExecutor_1 = require("./StructuredSagaExecutor");
const types_1 = require("../types");
/**
* Orchestrator for executing Sagas with structured context
* The context is structured as:
* {
* global: { ... },
* steps: {
* "Step Name": {
* input: { ... },
* output: { ... },
* compensation: { ... }
* }
* }
* }
* @template T Type of the input data
* @template R Type of the result data
*/
class StructuredSagaOrchestrator extends Saga_1.Saga {
/**
* Creates a new StructuredSagaOrchestrator
* @param definition Saga definition to orchestrate
* @param options Saga options
* @param stateStore Optional state store for persistence
*/
constructor(definition, options = {}, stateStore) {
super(options);
this.definition = definition;
this.stateStore = stateStore;
}
/**
* Executes the Saga
* @param initialData Initial data for the Saga
*/
async execute(initialData) {
try {
// Update context with initial data
if (initialData) {
// Structure the initial data
const structuredData = this.structureInitialData(initialData);
this.updateContext(structuredData);
}
else {
// Initialize empty structured data
this.updateContext({
global: {},
steps: {}
});
}
// Save initial state if state store is provided
if (this.stateStore) {
await this.stateStore.save(this.getId(), this.getContext());
}
// Create executor and execute the Saga
const executor = new StructuredSagaExecutor_1.StructuredSagaExecutor(this.definition, this.getContext());
const result = await executor.execute();
// Update context with result
this.context = result;
// Update state store if provided
if (this.stateStore) {
await this.stateStore.update(this.getId(), this.context);
}
return this.getContext();
}
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();
}
}
/**
* Structures the initial data into the format:
* {
* global: initialData,
* steps: {}
* }
* @param initialData Initial data
*/
structureInitialData(initialData) {
// If the data is already structured, return it as is
if (initialData && typeof initialData === 'object' &&
'global' in initialData && 'steps' in initialData) {
return initialData;
}
// Otherwise, structure it
return {
global: initialData || {},
steps: {}
};
}
/**
* 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);
}
// Create executor and execute compensation
const executor = new StructuredSagaExecutor_1.StructuredSagaExecutor(this.definition, this.getContext());
const result = await executor.execute();
// Update context with result
this.context = result;
// Update state store if provided
if (this.stateStore) {
await this.stateStore.update(this.getId(), this.context);
}
return this.getContext();
}
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();
}
}
}
exports.StructuredSagaOrchestrator = StructuredSagaOrchestrator;