WaitCoordinator
Runs commands and waits for their chains (–).
On the node a command arrives at, execute and stream check its wait plan, register the wait in registry, execute the command with a wait context naming this node, and answer once the chain is complete, has failed, or the timeout runs out:
ACCEPTED and COMMITTED are reached here, from the kernel's outcome; a HANDLED hop by a signal from the subscription it names, which finds the wait context on the log entry.
The results the decide function put come with the command's commit, at COMMITTED, from this node's execution or the owner's forward reply; each later hop's result of that command carries them, whichever node's subscription signalled it, so the default wait ends with them at the snapshot (see WaitState).
A rejection or failure ends the wait at once. A command that changed nothing reaches its later hops at once: there is no entry for a subscription to handle.
A duplicate request cannot be signalled again: its later hops happened, or will, under the first request's wait. A HANDLED hop of this context that ends the chain is checked from the subscription's checkpoint and the failure ledger (SubscriptionDirectory.hasHandled); otherwise the wait stops at COMMITTED,
duplicate.On timeout the answer is FAILED with ResultCodes.WAIT_TIMEOUT at the last hop reached. The deadline covers the whole wait, the command's execution included: the command is routed and executed in a supervised scope this coordinator owns, so a wait that times out before the command's outcome is known answers at ACCEPTED while the execution goes on, not cancelled half-way through a commit. Its outcome is then only logged; a retry with the same request id finds it, as the kernel deduplicates by request id. A command withdrawn because the deadline passed while it waited in its lane or before it was forwarded ends the wait the same way, whichever noticed the deadline first.
The deadline is the wait's, not its caller's: the runtime's own deadline thread (deadlines) ends the wait when it passes, whatever the caller's coroutine context. A caller's own timers, such as a WebFlux handler's, run in
Dispatchers.Unconfinedon kotlinx's oneDefaultExecutorthread, which also runs inline whatever such a timer resumes, so one held-up continuation there would hold every such deadline up. The wait itself runs in this coordinator's execution context, so neither the signals nor the deadline run its caller's code.A plan the runtime cannot follow is rejected before the command runs (ResultCodes.WAIT_INVALID), including an explicit snapshot hop for an aggregate without a snapshot subscription; only the default plan (me.ahoo.wow.api.result.WaitPlan.DEFAULT) waits for COMMITTED there instead.
forward runs a command derived on the way, such as by a saga, with the wait context it inherited: it sends the command's own results to the waiting node through signals instead of answering them.
Which subscriptions a chain may name, and their kinds, come from directory, until the Manifest gives them.
Where the command runs is router's choice: here, through executeHere, or on its partition's owner, which executes it with the same wait context and replies with its Settlement; either way the wait goes on here, and the later hops are signalled here.
The commands of the types topicRouter routes take the topic router instead: the command is written to its context's command topic, with the wait context, and the wait reaches ACCEPTED once the broker acknowledged it, durable from then on; the owner of its log partition executes it from the topic (me.ahoo.wow.runtime.command.CommandIntake) and signals its COMMITTED result and the later hops here, as for a saga's command. A broker that does not acknowledge it before the deadline ends the wait at ACCEPTED, FAILED. Only the commands admitted here take it: forward routes a saga's, an intake's and a timer's command as before, since the intake that reads the topic forwards what it reads.
The executions outlive their waits, so a node that stops joins them before it closes its executor, then closes the coordinator.
Constructors
Properties
The tuning of the waits started here.
This node, as signals address it. A me.ahoo.wow.runtime.node.ServiceNode that learns its internal address only once its internal port is bound sets the origin's address then, before it starts.
Functions
Accepts command, whose wait plan has only an ACCEPTED hop (isAcceptedOnly, a chain that is always valid), and returns its result at ACCEPTED at once. The command is routed and executed in scope, apart from the caller, with no wait context, so nothing is signalled about it; its outcome is only logged. Not durable: a node that stops before running it loses it.
Sends command, whose plan has only an ACCEPTED hop, as relay does, and returns its result at ACCEPTED once the broker acknowledged it; FAILED at ACCEPTED when it did not within the plan's timeout (sendThrough).
Executes command on model's aggregate and returns the result it ends its wait with: the last one stream would emit. It runs in this coordinator's execution context as stream does, without the channel and producer coroutine a flow moved to another context takes: a caller that wants the final result only pays for that.
Executes command on model's aggregate on this node, with the wait context it arrived with, and settles what it reaches at once: its result at COMMITTED, then its next HANDLED hop when that is already reached (a command that changed nothing appended no entry to handle; a duplicate whose subscription is past it). The node a command arrived at runs it so when its router chooses this node, and the owner of its partition runs it so for a forward.
Executes command, derived on the way of a wait (by a saga, or later sent from another context), or sent by a timer, on model's aggregate with the wait context it inherited, and signals its results to the waiting node: ACCEPTED when the context waits for it, then COMMITTED or the failure, then the later hop it reached at once. Without a context, or past its deadline, it only executes.
Sends command, admitted here for an aggregate of another service's context (a peer's), to its context's command topic through relay, and emits a result for each hop of its wait plan as it is reached, as the topic router's commands do: ACCEPTED once the broker acknowledged it, durable from then on; the target's intake executes it and signals its COMMITTED result here. function names the command in the results this node makes. The command's plan has only ACCEPTED and COMMITTED hops of its context: admission refuses any other.
Executes command on model's aggregate and emits a result for each hop of its wait plan as it is reached, one per command: a hop after a saga's emits one result for each command the saga derived, as each one reaches it, in the order they arrive, and is complete with the last of them. The command is executed when the flow is collected.