跳转到内容
简体中文

CassandraJournal

此内容尚不支持你的语言。

Defined in: src/persistence/journals/CassandraJournal.ts:48

Journal backed by Apache Cassandra or ScyllaDB — same CQL protocol, one plug-in serves both. Schema:

  • composite partition key (persistence_id, partition_nr) — keeps individual partitions bounded even for long-lived event streams;
  • clustering column sequence_nr for in-stream ordering;
  • a small metadata row per persistence_id tracking max_sequence_nr.

Appends are serialized by a lightweight transaction on the metadata row: the writer claims its sequence range with a conditional statement before a single event is written, so two writers that both read head N can never both proceed (#475). A plain read-check would not be enough — a Cassandra INSERT is an upsert, so the loser of that race would silently overwrite the winner’s event instead of being rejected the way the relational backends’ primary key rejects it. Costs one Paxos round-trip per append; lightweightTransactions: false trades the guarantee back for the round-trip.

new CassandraJournal(options): CassandraJournal

Defined in: src/persistence/journals/CassandraJournal.ts:60

CassandraJournalOptions

CassandraJournal

get serializer(): Serializer<unknown> | undefined

Defined in: src/persistence/journals/CassandraJournal.ts:68

The configured payload serializer — read by CassandraQuery so tag reads decode like the journal.

Serializer<unknown> | undefined


get tagIndexTable(): string

Defined in: src/persistence/journals/CassandraJournal.ts:383

Side-table name used when useTagIndex is set — visible so CassandraQuery can target it directly.

string


get useTagIndex(): boolean

Defined in: src/persistence/journals/CassandraJournal.ts:385

Whether dual-writes to the tag-index side table are enabled.

boolean

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

Defined in: src/persistence/journals/CassandraJournal.ts:126

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/journals/CassandraJournal.ts:368

Best-effort teardown; idempotent.

Promise<void>

Journal.close


delete(persistenceId, toSeq): Promise<void>

Defined in: src/persistence/journals/CassandraJournal.ts:295

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/CassandraJournal.ts:290

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

string

Promise<number>

Journal.highestSeq


persistenceIds(): Promise<string[]>

Defined in: src/persistence/journals/CassandraJournal.ts:312

Persistence IDs currently known to the journal (useful for projections).

Promise<string[]>

Journal.persistenceIds


persistenceIdsPaginated(afterPersistenceId, limit): Promise<string[]>

Defined in: src/persistence/journals/CassandraJournal.ts:341

A clustering-column range over the all_persistence_ids partition.

PRIMARY KEY (tag, persistence_id) makes persistence_id the clustering column of the single '_all' partition, so AND persistence_id > ? LIMIT ? is a seek into that partition’s sorted run — not the token(persistence_id) scan over events an earlier sketch of this called for, which would have paid a coordinator fan-out per page and handed back ids in ring order, in which no cursor is monotonic.

The single partition is itself a scaling limit at very large id counts — one replica set owns every id — but that is the shape persistenceIds() already had, and bucketing it is a schema migration rather than a paging concern.

string | undefined

number

Promise<string[]>

Journal.persistenceIdsPaginated


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

Defined in: src/persistence/journals/CassandraJournal.ts:254

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


start(): Promise<void>

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

Explicitly connect + ensure schema. Called lazily on first use. Single-flight: concurrent callers share one in-flight start; a failed start clears the guard so a later call can retry.

Promise<void>