MongoFailureLedger

class MongoFailureLedger(client: MongoClient, databaseName: String, collection: String = DEFAULT_COLLECTION, dispatcher: CoroutineDispatcher = VirtualThreads.dispatcher, service: String = DEFAULT_SERVICE, ddl: Ddl = Ddl.AUTO, operationTimeout: Duration = MongoTimeouts.OPERATION) : FailureLedger

The FailureLedger of one service on MongoDB (documentation/designs/04-subscriptions.md §2), in the service's own database: one document per parked (subscription, aggregate), keyed by a unique index on (service, subscription context, subscription, context, aggregate name, tenant, id). The key starts with service, the service the ledger is of, then the subscription's context and name (SubscriptionId): services that share a database, and subscriptions of one name in two contexts, see and resolve only their own entries. The collection's layout is recorded as format FORMAT (MongoFormat); a collection of another format, an earlier one among them, is refused, not converted.

Every write is one single-document operation. A park is a conditional upsert (see conditionalUpsert) whose filter admits only a later stored from version, so concurrent or replayed parks converge on the earliest without a transaction; a repark is one updateOne without upsert, both setting the source position of a Kafka-sourced subscription's entry, null for the log's; a resolve is one findOneAndDelete. A park writes the retry state only when it inserts the document, at revision 0 (one pipeline update); an amendment is one findOneAndUpdate returning the amended document at the next revision, its filter carrying the revision read when it claims, takes or schedules. No collation is set: MongoDB then compares strings by their UTF-8 bytes, which is code point order, so list pages in the order the contract asks for.

Besides the key index, DUE_INDEX on (service, subscription, partition, next attempt) answers due, and TENANT_INDEX on (service, subscription, tenant, then the key) answers a tenant's list in its order, a subscription being its context and name.

Calls run on dispatcher, virtual threads by default.

Constructors

Link copied to clipboard
constructor(client: MongoClient, databaseName: String, collection: String = DEFAULT_COLLECTION, dispatcher: CoroutineDispatcher = VirtualThreads.dispatcher, service: String = DEFAULT_SERVICE, ddl: Ddl = Ddl.AUTO, operationTimeout: Duration = MongoTimeouts.OPERATION)

Functions

Link copied to clipboard
open suspend override fun amend(subscription: SubscriptionId, ref: AggregateRef, amendment: ParkedAmendment): ParkedAggregate?
Link copied to clipboard
open suspend override fun count(subscription: SubscriptionId, max: Int): Int
Link copied to clipboard

Claims the collection's format (MongoFormat) and creates its indexes when missing: the key index, which also serves list's order and count, DUE_INDEX and TENANT_INDEX.

Link copied to clipboard
open suspend override fun due(subscription: SubscriptionId, partitions: Collection<Int>, now: Long, after: AggregateRef?, limit: Int): List<ParkedAggregate>
Link copied to clipboard
open suspend override fun list(subscription: SubscriptionId, after: AggregateRef?, limit: Int, tenantId: String?): List<ParkedAggregate>
Link copied to clipboard
open suspend override fun park(entry: ParkedAggregate): Boolean

One pipeline update, so that a document it inserts takes entry's retry state at revision 0, and one it replaces keeps its retry state, takes the next revision and is no longer scheduled: a document is inserted when it has no RECOVERABLE, which every stored entry has.

Link copied to clipboard
open suspend override fun parked(subscription: SubscriptionId, ref: AggregateRef): ParkedAggregate?
Link copied to clipboard
open suspend override fun repark(entry: ParkedAggregate, from: Int): Boolean
Link copied to clipboard
open suspend override fun resolve(subscription: SubscriptionId, ref: AggregateRef, partition: Int): ParkedAggregate?
Link copied to clipboard
open suspend override fun resolveAnywhere(subscription: SubscriptionId, ref: AggregateRef): ParkedAggregate?