SubscriptionBindings

Adapts the handlers of annotated processors (ProcessorBinding) into the subscriptions of a me.ahoo.wow.runtime.node.ServiceNode: one per handler, in the bounded context its processor's module belongs to, by context in processors.

  • Name, filter and start: the subscription is the handler's ProcessorBinding.name, processor.function, of the aggregates of the context whose state is the handler's state type (every aggregate for StateEvent<*>), of any of their events: a handler's signature names its state, not its events. It starts where the handler says (ProcessorBinding.startIn: as @OnEvent(start) declares, else a projection or a handler of another context's stream from the beginning, a reactor or a saga of the context's own log from the end). A state type no aggregate of the context has fails the node's assembly.

  • What the handler gets: the entry decoded by EntryDecoder.stateEvents, each subscription the state reader of its own name (stateReaders): its events decoded and upgraded, and the state after the commit, a copy decoded from the context's shared view for this handler alone; with the context of its kind, whose me.ahoo.wow.api.subscribe.ExecutionId is (subscription, aggregate, version).

  • Calls: in the subscription's coroutine, or on a virtual thread for a @Blocking handler (ProcessorBinding.blocking).

  • Sagas execute what they derive through the context's wait coordinator (DerivedCommands) and report the commands' ids, so a wait chain may go on after their hop. A command to another context is sent to its command topic, asking for a receipt of its rejection when the saga has an @OnRejected or an @OnCommitted handler for it, and of its commit when it has the latter; receipts hands those receipts to them.

  • Rejections of what a saga derives are business outcomes, neither retried nor, when the saga handles them, parking: each derived command is settled on its own, a rejected one stopping none of the others, and the wait at the saga's hop ends REJECTED with the first one's error (HandledEntry.rejection). The saga's @OnRejected handler for each rejected command, if any, gets it on its own (SagaReceipts, which executes what it derives to compensate); the rejections no handler takes park the aggregate once, at once, listing every one (DerivedCommandRejectedException).

  • Commits of what a saga derives in its own context go to the saga's @OnCommitted handler of the command, if any, right after the commands are executed, in their order; what it derives is executed too, but is not among the commands the saga's hop reports: the wait follows the committed command, not the receipt.

  • Schedules a saga's handler makes (me.ahoo.wow.api.subscribe.SagaContext.schedule) are derived commands too, the system commands wow.schedule.Set and wow.schedule.Cancel to their target, executed in order with the others to that target; the command they schedule is named by the context's models and Manifests (ContextNode.commandTypes). A target that does not exist rejects one, which goes to @OnRejected.

  • Jobs: a saga's @OnSchedule handler (ProcessorBinding.job) is a saga handler of the context's built-in job aggregate, <context>.schedule, which the node adds for the jobs its handlers run: its subscription reads its job's instances alone, by their ids (ScheduleJobModel.instanceIds), each tick is handed to it, and what it derives is executed as any saga's.

  • Failures: a handler that throws, or a state that cannot be read, is retried, then parks its aggregate, as any subscription (me.ahoo.wow.runtime.subscription.SubscriptionOptions.retry); a handler's @Retry (ProcessorBinding.retry) is its subscription's own budget (Subscription.retry).

  • Other contexts' streams: a handler whose @OnEvent(aggregates) names another context's (ProcessorBinding.isSourced) is sourced: its subscription reads the published streams of those aggregates from their topics. It gets the record's facts and published events (me.ahoo.wow.spi.state.StateEventPayload, each its name, revision and JSON payload), and the published state decoded into its state type, or null when the upstream publishes without it, which only a handler of a nullable state takes. It reads no state view of its own context. It belongs to its own context (Subscription.context): a wait the record carries names its hop there, and it signals that hop to the wait's origin as a subscription of its own context would; a saga's commands carry the rest of the chain on (DerivedCommands.waitOf).

Constructors

Link copied to clipboard
constructor(processors: Map<String, List<ProcessorBinding<*>>>)

Types

Link copied to clipboard

Functions

Link copied to clipboard
open override fun committedHandlers(context: String): Set<String>

The names of the @OnCommitted handlers of context's sagas, each a hop of its waits.

Link copied to clipboard
open override fun jobs(context: String): Map<String, ScheduleJob>

The jobs of context's @OnSchedule handlers, by the name of the subscription that runs each, asked before the context is assembled: the node adds the built-in job aggregate <context>.schedule deciding them, starts the SYSTEM and SHARDED ones, and gives each subscription its job's settings (ServiceNodeOptions.schedules). None by default.

Link copied to clipboard
open override fun receipts(context: ContextNode): ReceiptHandler?

The @OnRejected and @OnCommitted handlers of context's sagas, for the receipts of the commands they sent to other contexts; null when none of its sagas has one.

Link copied to clipboard
open override fun sourced(context: ContextNode): List<SourcedSubscription>

The subscriptions of context that read the published streams of other contexts' aggregates, each with the aggregate types it reads. The node finds each type's topic in its contracts (me.ahoo.wow.runtime.contract.ContractDirectory.publishedOf) and reads it (SourceTopics). None by default.

Link copied to clipboard
open override fun stateReaders(context: String, models: List<AggregateModel<*>>): Map<String, Set<AggregateType>>

The state consumers among the subscriptions of context, by the reader name each reads the shared states with (ContextNode.stateReader), with the aggregate types it reads: a view is evicted once every reader of its type passed it, or it ages out. By default one reader named after this factory's class, of the types viewTypes names: it passes nothing unless its subscriptions read under that name, so their views only age out. A factory that overrides it also overrides viewTypes with the types it names.

Link copied to clipboard
open override fun subscriptions(context: ContextNode): List<Subscription>
Link copied to clipboard
open override fun viewTypes(context: String, models: List<AggregateModel<*>>): Set<AggregateType>

The aggregate types among context's models whose state after each commit the subscriptions read: the context's executor keeps their shared states (ContextNode.views), asked before the context is assembled. None by default.