LedgerPublisher

Publishes a service's failure ledger to the ops context: each entry as a LedgerEntry to the ops aggregate Ledger.parkedId names, through the command topic of LedgerPublishing.context (send), and each entry that is no longer parked as a LedgerResolution.

  • When: at once when an entry parks or spends its retries (the node's ParkedNotifier), and when an operator's ledger command acts on one (parked, resolved); and on every scan, every LedgerPublishing.interval, the reconciliation loop: every entry whose partition this node runs (ParkedOps.owns) is published again, and an entry this node published that has since left the ledger, not to another owner, is published as resolved. A record that is lost (the broker down, the node killed) is so published again; one entry's failure does not stop the others. A resolution whose send failed is kept in memory as it was and sent again by each scan of this node, whether or not it still runs the partition, until it is delivered, the aggregate is published parked again first, or the node stops.

  • Idempotence: a record's request id is deterministic: a digest of the entry's ops id and its content, and of when this node first saw that content, so a record sent twice is one request to the ops aggregate, while an entry that comes back to an earlier content (an operator's request taken, say) is a new request. The ops aggregate ignores a record that changes nothing, so the records a scan sends again leave its log as it is.

  • Operator: the records are a framework component's, system:ledger.

After a restart the node no longer knows what it published, nor the resolutions it had not sent yet: an entry resolved while it was down, or whose resolution it had not delivered, stays parked in the ops view until an operator acts on it there, which the owning service answers with LedgerResolution.NOT_PARKED.

With available (an LedgerPublishing.automatic publishing), it publishes only while available says the ops context can take the records: asked at start and every availability after. While it cannot, nothing is sent and the entries stay in the ledger; once it can, a scan at once publishes them all. Each change is logged once.

Types

Link copied to clipboard
object Companion

Properties

Link copied to clipboard

Hears when an entry parks or spends its retries, and publishes it as it now stands.

Link copied to clipboard

Whether the records are sent: always without available, else as it last said.

Functions

Link copied to clipboard
suspend fun <T> acting(subscription: SubscriptionId, ref: AggregateRef, action: suspend () -> T): T

Runs action, an operator's action on subscription's entry of ref that publishes what came of it, while the scans leave the entry alone: a scan between the action resolving the entry and publishing its outcome would otherwise publish it as LedgerResolution.RESOLVED first, and the ops view keeps the first resolution.

Link copied to clipboard
suspend fun parked(view: ParkedView)

Publishes view's entry as parked.

Link copied to clipboard
suspend fun resolved(subscription: SubscriptionId, ref: AggregateRef, outcome: String, failedAt: Long? = null)

Publishes that subscription no longer parks ref, since outcome; failedAt the parking's, when known.

Link copied to clipboard
suspend fun scan()

Publishes every entry whose partition this node runs, and as resolved each one it published before that has left the ledger since; an entry an operator's action is acting on is the action's to publish.

Link copied to clipboard
fun start()

Starts the reconciliation loop: a scan now and every LedgerPublishing.interval; with available, asks it now and every availability first.

Link copied to clipboard
suspend fun stop()

Stops the reconciliation loop, waiting for a scan that is running.