Package-level declarations

Types

Link copied to clipboard
class BackpressureOptions @InternalWowApi constructor(val maxAttempts: Int = 20, val initialBackoff: Duration = 100.milliseconds, val maxBackoff: Duration = 10.seconds, val jitter: Double = 0.5, val minConcurrency: Int = 1)

How a subscription answers backpressure: a failure classified me.ahoo.wow.spi.subscription.FailureClass.BACKPRESSURE, a downstream that is up but asked to be called later. The entry is retried at most maxAttempts times, then its aggregate parks as after any spent budget; it never pauses the partition. The wait before the next attempt starts at initialBackoff, doubles to at most maxBackoff, is shortened by up to jitter (a share, 0 to 1) at random so the lanes do not retry in step, and is at least the downstream's Retry-After. Meanwhile the partition is throttled: each backpressure halves the handlings it runs at once, down to minConcurrency, and each success raises it by half again, back to the in-flight bound (at once when no handling waits under the limit).

Link copied to clipboard

Turns a committed stream into the entry a handler receives. It runs inside the handler's retries, so a stream that cannot be decoded is retried and then parks its aggregate like a failing handler.

Link copied to clipboard
data class HandledEntry(val derived: List<String> = emptyList(), val rejection: ErrorInfo? = null)

What a subscription's handler did with an entry, as its hop reports it: the ids of the commands a saga derived, and the rejection of one of them, a business outcome the saga handled: the entry is done with, and the wait at the hop ends REJECTED with it instead of going on.

Link copied to clipboard
data class OrphanCheckpoints(val group: String, val name: String, val positions: List<Checkpoint>, val parked: Int)

The checkpoints a subscription of group left behind: name, a name the group no longer has, saved its positions, one per partition, and has parked entries under it, counted up to a limit. A checkpoint holds a subscription's name alone, without its context.

Link copied to clipboard
class ParkedNotice @InternalWowApi constructor(val kind: ParkedNotice.Kind, val group: String, val entry: ParkedAggregate, val spec: ParkedRetrySpec, val at: Long)

What a ParkedNotifier hears: kind happened at at (epoch milliseconds) to entry, parked by a subscription of context run in lease group, whose retry spec is spec.

Link copied to clipboard
fun interface ParkedNotifier

Hears what happens to a subscription's parked entries that an operator should know of (9.x's WeCom webhook): an aggregate parked, and an entry whose automatic retries are spent. It is told on the node that parked or retried the entry, once per change of the ledger, best effort: a notifier that fails is logged, and the subscription goes on. A notifier should return quickly; it runs beside the subscription, not in its way.

Link copied to clipboard
class ParkedRetryOptions @InternalWowApi constructor(val spec: ParkedRetrySpec = ParkedRetrySpec(), val specs: Map<SubscriptionId, ParkedRetrySpec> = emptyMap(), val scanInterval: Duration = 10.seconds)

How a SubscriptionRuntime retries its parked entries over the long horizon (9.x CompensationScheduler): every scanInterval it reads its subscriptions' ledger entries and, in each partition it runs, retries those whose next retry is due (me.ahoo.wow.spi.ledger.ParkedAggregate.nextRetryAt) and runs the requests an operator left on them.

Link copied to clipboard
data class PausedPartition(val group: String, val subscription: String, val partition: Int, val since: Long, val reason: String, val failure: String)

A subscription's partition paused on a systemic failure: since since (epoch milliseconds), for reason, subscription of the subscription group handles nothing in partition but one probe at a time, until a handling succeeds. reason says it in full, the failure's message and aggregate included, for the log; failure is the class name of the failure that paused it, all the health details show, since a message may carry data.

Link copied to clipboard
class RetryPolicy @InternalWowApi constructor(val maxAttempts: Int = HandlerRetry.DEFAULT_MAX_ATTEMPTS, val initialBackoff: Duration = 100.milliseconds, val maxBackoff: Duration = 5.seconds, val multiplier: Double = 2.0, val timeout: Duration = Duration.INFINITE)

How a failing call is retried: at most maxAttempts calls in all, waiting initialBackoff after the first failure and multiplier times longer after each next one, never longer than maxBackoff. A handler's attempt that runs longer than timeout is cancelled and counts as failed; infinite by default.

Link copied to clipboard
data class SubscribedEntry(val stream: EventStreamRecord, val position: LogPosition?, val events: List<Any>, val transport: Transport? = null, states: SharedStateReader? = null, val published: StateEventRecord? = null, val message: Any? = null, val imported: Boolean = false)

What a handler receives: one committed stream (its ref, version, scope and events), at its log position, with its events as the subscription's EntryDecoder read them and the transport metadata appended with it.

Link copied to clipboard

A subscription: a name, a filter and exactly one handler. The checkpoint belongs to the name, so one handler never shares a checkpoint with another; a replay or a blue-green rebuild is a new name starting from the beginning.

Link copied to clipboard
data class SubscriptionFilter(val context: String, val aggregates: Set<String> = emptySet(), val events: Set<String> = emptySet(), val ids: Set<String> = emptySet())

The streams a subscription handles: those of one bounded context, of the aggregates named (every aggregate of the context when empty), of the aggregates whose id is in ids (any id when empty: a job's subscription reads its job's instances alone), holding at least one event whose stored name is in events (any event when empty). Event names are the names the log stores (context.aggregate.Event). Without models a renamed event must be listed under its former names too; resolve adds them from the models. An entry outside the filter still moves the checkpoint, its state never read.

Link copied to clipboard
class SubscriptionOptions @InternalWowApi constructor(val maxInFlight: Int, val retry: RetryPolicy = RetryPolicy(), val checkpointInterval: Duration = 1.seconds, val stopTimeout: Duration = 10.seconds, val readRetry: RetryPolicy = RetryPolicy( maxAttempts = 5, initialBackoff = 100.milliseconds, maxBackoff = 5.seconds ), val starts: Map<SubscriptionId, SubscriptionStart> = emptyMap(), val parked: ParkedRetryOptions = ParkedRetryOptions(), val retries: Map<SubscriptionId, HandlerRetry> = emptyMap(), val systemic: SystemicFailureOptions = SystemicFailureOptions(), val backpressure: BackpressureOptions = BackpressureOptions(), val maxCatchUps: Int = DEFAULT_MAX_CATCH_UPS)

The tuning of a SubscriptionRuntime.

Link copied to clipboard

The partitions a node's subscriptions have paused on a systemic failure, as the health model reads them: a paused partition is not a failed node, but one its operator wants to see, and that stays paused as long as what it depends on is down.

Link copied to clipboard
data class SubscriptionPosition(val subscription: String, val partition: Int, val watermark: Long)

Where subscription stands in partition of its source: every entry up to the sequence watermark is complete.

Link copied to clipboard

Runs the subscriptions of one subscription group over the partitions this node owns (–§3).

Link copied to clipboard

Where a subscription that has no checkpoint yet in a partition starts: the host's override of its handler's StartFrom (wow.subscriptions."<name>".start, SubscriptionOptions.starts). A subscription that has a checkpoint goes on from it whatever this says.

Link copied to clipboard
class SystemicFailureOptions @InternalWowApi constructor(val failingAggregates: Int = 3, val window: Duration = 10.seconds, val initialBackoff: Duration = 1.seconds, val maxBackoff: Duration = 30.seconds)

When a subscription pauses a partition on a systemic failure: at once on a failure classified me.ahoo.wow.spi.subscription.FailureClass.SYSTEMIC; and when failingAggregates different aggregates failed with a recoverable one within window, with no handling succeeding since (0 turns that off). While paused, one attempt at a time probes whether what failed is back, the first initialBackoff after the pause, each next one twice as long after the previous one failed, at most maxBackoff.

Link copied to clipboard
data class ThrottledPartition(val group: String, val subscription: String, val partition: Int, val limit: Int, val since: Long)

A subscription's partition throttled by backpressure: since since (epoch milliseconds), subscription of the subscription group runs at most limit handlings at once in partition.