InMemorySagaJournal

Reference implementation of SagaJournal backed by a ConcurrentHashMap with per-RunId locking.

Thread-safety model

Different RunIds may append concurrently without contention — each run has its own Mutex. Within a single RunId, appends are serialized by the per-run lock. Lock creation uses ConcurrentHashMap.computeIfAbsent, which is itself thread-safe.

Codec placement (D3)

This implementation stores payload P directly. PayloadCodec is never called here. Persistent adapters (Room, JDBC, file) accept a PayloadCodec in their own constructor and convert at persistence boundaries. This keeps in-memory usage fast and free of serialization concerns.

Usage

val journal = InMemorySagaJournal<OrderEvent>()

// Plug into a saga executor (T006 wires this):
val saga = sagaExecutor(journal = journal, runId = RunId("order-42")) { ... }

Parameters

P

Payload type stored verbatim without encoding.

Constructors

Link copied to clipboard
constructor()

Functions

Link copied to clipboard
open suspend override fun append(entry: JournalEntry<P>): JournalOutcome<AppendedEntry<P>>

Appends entry to this run's in-memory list.

Link copied to clipboard
open suspend override fun head(runId: RunId): JournalOutcome<ChainHead?>

Returns a ChainHead pointing at the last entry for runId, or null if unknown.

Link copied to clipboard
open suspend override fun read(runId: RunId): JournalOutcome<List<JournalEntry<P>>>

Returns all entries for runId as an immutable snapshot.

Link copied to clipboard
open suspend override fun since(runId: RunId, seq: Long, limit: Int): JournalOutcome<List<JournalEntry<P>>>

Returns up to limit entries whose JournalEntry.seq>= seq, in ascending seq order.

Link copied to clipboard
suspend fun <P> SagaJournal<P>.verify(runId: RunId, fromSeq: Long = 0, toSeq: Long = Long.MAX_VALUE, pageSize: Int = DEFAULT_VERIFY_PAGE_SIZE): JournalOutcome<VerifyResult>

Verifies the tamper-evident hash chain for runId over entries with seq in [fromSeq, toSeq].