ISagaStore
Overview
Section titled “Overview”ISagaStore is the persistence interface for saga state. The bus calls into it whenever a saga is loaded, created, updated, or completed. Implementations are responsible for serialising the saga-data object to whatever underlying store they wrap (in-memory Map, MongoDB collection, SQL table, etc.) and for enforcing optimistic-concurrency semantics via a ConcurrencyToken.
The two error types ConcurrencyError and DuplicateSagaError are exported from @serviceconnect/core. Implementations should throw them at the documented points so the bus can apply the correct retry/poison-handling behaviour.
Import
Section titled “Import”import type { ConcurrencyToken, FoundSaga, ISagaStore, ProcessData,} from '@serviceconnect/core';import { ConcurrencyError, DuplicateSagaError } from '@serviceconnect/core';Signature
Section titled “Signature”export interface ProcessData { correlationId: string;}
export type ConcurrencyToken = string;
export interface FoundSaga<TData extends ProcessData> { readonly data: TData; readonly concurrencyToken: ConcurrencyToken;}
export interface ISagaStore { findByCorrelationId<TData extends ProcessData>( dataType: string, correlationId: string, ): Promise<FoundSaga<TData> | undefined>;
insert<TData extends ProcessData>( dataType: string, data: TData, ): Promise<ConcurrencyToken>;
update<TData extends ProcessData>( dataType: string, data: TData, expectedToken: ConcurrencyToken, ): Promise<ConcurrencyToken>;
delete(dataType: string, correlationId: string): Promise<void>;}Members
Section titled “Members”findByCorrelationId(dataType, correlationId)— look up an existing saga by itsdataType(the registered data-type name) andcorrelationId. Returns{ data, concurrencyToken }when a row exists,undefinedotherwise. The returneddatashould be the freshly deserialised state — handlers will mutate it in place — andconcurrencyTokenis whatever opaque value letsupdatedetect a concurrent write.insert(dataType, data)— create a new saga row. Returns the initialConcurrencyToken. Implementations must throwDuplicateSagaErrorif a row already exists for(dataType, data.correlationId). ADuplicateSagaError— like any insert failure — surfaces as a non-terminal failure, so the message is retried by the normal retry policy; on redeliveryfindByCorrelationIdfinds the now-existing row and the bus takes the update path. There is no immediate in-process load-and-update fallback within a single delivery.update(dataType, data, expectedToken)— write a new version of the saga row. Implementations must throwConcurrencyErrorifexpectedTokendoes not match the token currently in storage (optimistic concurrency). On success, return the new token for the next round-trip.delete(dataType, correlationId)— remove the row. Called when a saga marks itself complete. Safe to no-op if the row no longer exists.