Pular para o conteúdo
Português (BR)

DynamoDbJournal

Este conteúdo não está disponível em sua língua ainda.

Defined in: src/persistence/journals/DynamoDbJournal.ts:70

Journal backed by Amazon DynamoDB.

Optimistic concurrency is a conditional write, and it is stronger than the relational backends’. append sends every event in one TransactWriteItems, each Put carrying ConditionExpression: attribute_not_exists(pid) — “only if this (pid, seq) item does not exist”. A racing writer therefore cannot win a partial append: the transaction is atomic across all items, so either the whole batch lands or none of it does, and the cancellation is translated into JournalConcurrencyError. The preceding head read is only an optimization that turns the common stale-append into one cheap query instead of a rejected transaction.

That atomicity is why this backend needs no equivalent of MongoDB’s “a mid-batch failure can persist a prefix” caveat.

The high-water mark is an item, not a table. Compaction stores deletedTo at the reserved sort key 0, updated with ConditionExpression: attribute_not_exists(deletedTo) OR deletedTo < :value, which is GREATEST / $max expressed as a condition: a lower value is rejected, and the rejection is expected rather than an error.

Reads and deletes page. DynamoDB returns at most 1 MB per Query, so a recovery over a long stream loops on LastEvaluatedKey; skipping that is the classic way to silently truncate a replay.

Being a remote, cross-process store, it exposes no in-process event bus, so the query layer polls. There is no indexed tag path yet — see the class docs for what that would take.

new DynamoDbJournal(options?): DynamoDbJournal

Defined in: src/persistence/journals/DynamoDbJournal.ts:75

DynamoDbJournalOptions = {}

DynamoDbJournal

DynamoDbStore.constructor

append<E>(persistenceId, events, expectedSeq, tags?): Promise<PersistentEvent<E>[]>

Defined in: src/persistence/journals/DynamoDbJournal.ts:95

Append events to the stream of persistenceId, enforcing optimistic concurrency: the current highest sequence number MUST equal expectedSeq or the call throws JournalConcurrencyError. Returns the written events with their assigned sequence numbers.

E

string

readonly E[]

number

readonly string[]

Promise<PersistentEvent<E>[]>

Journal.append


close(): Promise<void>

Defined in: src/persistence/LazyStore.ts:66

Best-effort teardown; idempotent.

Promise<void>

Journal.close

DynamoDbStore.close


delete(persistenceId, toSeq): Promise<void>

Defined in: src/persistence/journals/DynamoDbJournal.ts:200

Delete events up to and including toSeq — used when compacting past a snapshot. Only ever a prefix, so what survives is a suffix that read still returns contiguously, and sequence numbers never rewind: highestSeq keeps reporting the high-water mark afterwards.

string

number

Promise<void>

Journal.delete


highestSeq(persistenceId): Promise<number>

Defined in: src/persistence/journals/DynamoDbJournal.ts:191

Current highest sequence number for persistenceId — 0 if no events exist.

string

Promise<number>

Journal.highestSeq


persistenceIds(): Promise<string[]>

Defined in: src/persistence/journals/DynamoDbJournal.ts:230

No persistenceIdsPaginated counterpart, deliberately. Paging needs a sorted index over the ids, and a DynamoDB table has no order across partition keys at all — Scan hands rows back in hash order, and its LastEvaluatedKey cursor is not comparable to a persistence id. Slicing a scan by page would therefore return arbitrary, overlapping subsets; the query layer’s fallback (scan once, sort, cut) is the honest shape, and leaving the method off is what selects it.

Promise<string[]>

Journal.persistenceIds


read<E>(persistenceId, fromSeq, toSeq?): Promise<PersistentEvent<E>[]>

Defined in: src/persistence/journals/DynamoDbJournal.ts:162

Return the events in [fromSeq, …, toSeq], ascending by sequence number. toSeq defaults to the current highest sequence number. Both bounds are inclusive — fromSeq is the first event returned, not an “after” cursor.

Ordering and contiguity are part of the contract, and replay enforces them (#122). Consecutive entries must differ by exactly one, every sequenceNr must be a safe integer ≥ 1, and nothing may fall outside the requested window. delete compacts a prefix, never a hole in the middle, so a gap inside the returned slice can only mean a defect — a missing ORDER BY, a half-written append, a store someone else can write. replayState raises JournalIntegrityError instead of folding it, because an actor that recovers from a shuffled or holed stream reaches a state that never existed and then fails every later persist with a JournalConcurrencyError that has no visible cause.

E

string

number

number

Promise<PersistentEvent<E>[]>

Journal.read