Package-level declarations
Types
An after hook: runs after the decide function of every command it applies to, sees the same, not yet evolved state, and returns events appended after the command's own, in the same event stream. It does not run when the command is rejected. A hook the model builder makes runs after a system command (a lifecycle or wow.schedule one) only when it names it (AggregateModelBuilder.after). Like a decide function it keeps its form; a Suspending.blocking one runs on a virtual thread.
An aggregate type compiled into tables: what each command type runs and how it is named, how each event type evolves the state, and how each event type is named in the log. Built once, read on every command; the hot path only looks things up.
The Kotlin DSL of an aggregate model. Command and event types are named context.aggregate.Name after their class's @Name, else its simple name, unless a name is given: the name the compiler gives them, so a model written by hand stores what the Manifest says. A name given that disagrees with the class's @Name, or an aggregate named otherwise than its @AggregateRoot state class, fails here: the log would hold names the Manifest does not.
Several dependencies are of type, the candidates by their names, and none is the one to take: the parameter of building names one with a qualifier (@Name), or the host marks one primary.
What Kernel.executeBatch did with one command of a batch.
The dispatcher every @Blocking call runs on: a virtual thread per call (JDK 21). The kernel runs blocking decide functions and after hooks on it, the runtime its blocking subscription handlers and receipts, so a node has one of it.
An aggregate's state after its event stream version, with the metadata the kernel keeps beside it: its scope, the owner and space it has after that stream, which the next stream carries forward; whether it is deleted. Only the lifecycle commands change them. Its schedules are the rules of the schedules it keeps, by key: those its streams set and did not cancel.
What a command records of the caller that sends it, as admission derives it: the scope it acts in, the operator that sends it and the request facts of the caller, its application's among them. The command gateway, the edge and the test DSL derive them alike (of); the tenant is me.ahoo.wow.spi.tenant.TenantPolicy's.
A saga's handler let through the rejection of a synchronous call it made, which no @OnRejected handler of the saga takes: a business outcome, so the aggregate parks at once, without a retry, as for a derived command's rejection no handler takes, and a wait at the saga's hop ends REJECTED with the target's error.
Sends the synchronous calls of a saga's execution to other contexts: the runtime's HTTP client on a node, an answer of the test DSL in a domain module's test. call returns the target's result as it is, SUCCEEDED, REJECTED or FAILED, and throws a WowProblemException (failure) when it reaches none; ExecutionSagaContext.call turns the results that did not succeed into the handler's typed failures.
How the kernel finished a command; the runtime reads it, an application never does.
How a command type is named: context.aggregate.CommandName, the class's simple name unless the model gives another. The log records it with each event stream, and a request id reused by a command of another name is rejected rather than taken for a retry; renaming or moving the class does not change it.
Names the commands a decide function schedules for an aggregate of another type than its own: the full type name (context.aggregate.Command) of the command class sent to an aggregate of target, or null when none is known. The runtime names them from the context's models and the Manifests of the service and its peers.
One @OnCommitted handler of a saga, bound to its processor instance, the counterpart of RejectionBinding: what the compiler generates for each @OnCommitted function of a @Saga. It belongs to the saga's ProcessorBindings (ProcessorBinding.commits), since it takes the success receipts of the commands the saga's own handlers derive; like them, it knows no runtime.
One commit of an aggregate's history (Kernel.trace): its stream, the stream's events (but the retired ones) read as the model's current schema (upgraded), and the aggregate after it: its state as the event codec writes it (a tree, so a mutable state evolving further does not change it), its deleted mark and its declared access attributes in their stored form (EventCodec.accessOf).
The queries a subscription handler reads with (me.ahoo.wow.api.subscribe.SubscriptionContext.queries), by the tenant of the commit it handles: the node's query API on a node, a test's fake in a domain module's test.
A decide function, in the form its signature has. The kernel calls a Sync one directly, with no continuation and no dispatch; only a Suspending one runs as a coroutine call, and a Suspending.blocking one (@Blocking) on the kernel's blocking dispatcher, a virtual thread.
Where the parameters of the generated model factories come from: the domain services a command function takes besides its command. A ModelProvider resolves each when the host builds the models, once, at startup, so a missing one fails the start rather than a command. The port knows no DI framework: a host adapts its own container (Spring's bean factory, for one), and of serves tests and hosts without one.
The execution of a handler that derives commands, as its context: it turns the requests the handler returned into the commands the subscription sends, as me.ahoo.wow.api.subscribe.SagaContext describes, followed by those the handler recorded through its context (a saga's schedules), in the order it recorded them.
Turns events into what the log stores, and back. Events are named by the model, never by class name, so renaming or moving a class does not orphan its history. States go into and come out of snapshots the same way.
How an event type is named in the log and which schema revision the model reads it as.
Turns an event's payload of one revision into the next revision's, as an @Upgrade function does: the tree of a record as stored, numbers exact, in and out.
The context of a projection's or a reactor's handler for one execution; its queries are contextQueries' of the commit's tenant.
Whether the command the kernel executes in this coroutine runs on the owner of its log partition (C2 and C4), as the router that chose this node says:
The context of a saga's handler of a receipt: of the rejection of the command receiptOf, by an @OnRejected handler, or of its commit, by an @OnCommitted one. Handling the same receipt again, after a retry or a second delivery, derives the same requests, which the kernel does not decide twice: each command's id and request id are compensationId of receiptOf, this execution, and what it asks (its target, its command type and its business key or occurrence), as a saga's derived commands are keyed (ExecutionSagaContext.derivedId). Each command's causation is the command receiptOf, in the chain of its root (causation), and its operator and scope are that command's, and so are its headers, the request facts it inherited (me.ahoo.wow.api.decide.RequestFacts.PROPAGATED). It schedules, cancels and calls as every saga context does (ExecutionSagaContext): its schedules written by codec, its calls through calls.
The context of a saga's handler for one execution of the commit event. Each execution, a retry included, gets a new one, and each command it derives is keyed by what it asks (derivedId): its target, its command type and its business key or its occurrence among the commands of this execution with both. Handling the commit again derives the same request for each command it derives again, in whatever order, which the kernel does not decide twice (it deduplicates by request id). A domain module's tests build one to call a saga directly.
How a handler's failures are classified, by the runtime's subscriptions and by the test DSL alike: a handler's own @Retry(recoverable, unrecoverable) (HandlerRetry.classify) first, of the failure itself or, for an UnreadableEventException, of what the kernel could not read; then, for the failure and each of its causes in turn, each of classifiers in order, the first class one gives deciding; FailureClass.RECOVERABLE when none does. of orders them: the application's, then the modules' found on the classpath (MODULES), then the caller's own, then the built-in rules for Wow's SPI failures (BuiltInFailures). A HandlingRejectedException is no failure to classify: a business outcome, it parks the aggregate at once.
An attempt of subscription's handler at ref's version that ran longer than its budget's timeout (HandlerRetry.timeout, @Retry(timeout)): it was cancelled and counts as a failed attempt, retried like any other failure. The runtime's subscriptions and the test DSL throw it alike.
A handling that failed for a business reason, which no retry changes: a subscription does not retry it but parks the aggregate at once, and a wait at the hop ends REJECTED with error. A saga's call or derived command whose rejection no @OnRejected handler takes ends a handling so.
A saga's handler derived what is no derived request: an element that is no CommandRequest (a Command, another object), or a request with a wait or a timeout, which the subscription that sends it waits for none of. A defect in the saga, which no retry changes: the handling fails unrecoverable, so the aggregate parks at once.
The write kernel: turns one admitted command into at most one committed event stream (documentation/designs/02-write-path.md §1).
The tuning of a Kernel, set in code, not by configuration keys:
The binding index of one module: the aggregate models of its bounded context context, the handlers of its subscription processors (processors) and of its service routes (routes), and where its Manifest fragment is (fragment, META-INF/wow/manifest/<module>.json). The compiler generates one per module and registers it in META-INF/services/me.ahoo.wow.kernel.ModelProvider, so the host finds every module of the service with load, without scanning or reflecting.
One handler of an annotated subscription processor, bound to its processor instance: what the compiler generates for each @OnEvent function of a @Projection, @Reactor or @Saga, exposed by its module's ModelProvider.processors. It knows no runtime: the runtime compiles each into one subscription named name, processor.function.
A command an aggregate's lane hands to Kernel.executeBatch, with the wait context the runtime built for it.
One @OnRejected handler of a saga, bound to its processor instance: what the compiler generates for each @OnRejected function of a @Saga. It belongs to the saga's ProcessorBindings (ProcessorBinding.rejections), since it takes the rejections of the commands the saga's own handlers derive, not entries of the log; like them, it knows no runtime.
Rejection codes as the Manifest, results, receipts and HTTP name them: a decide function may reject with the local name of a code of its aggregate (invalid-item, a code without a dot, declared within its @AggregateRoot class), which the kernel qualifies with the deciding command's aggregate type (eshop-basket.basket.invalid-item) before anything else sees it; a code with a dot is full, and stays as it is.
The one shape of a command's rejection in the log, under the logger CATEGORY: a readable message, and the fields as SLF4J key-values named as the spans' attributes name them (CONTEXT, AGGREGATE, COMMAND, ERROR_TYPE, REQUEST_ID, and WITH_EVENTS for a decision's). A decision's rejection is a business outcome, at INFO (rejected); an admission's refusal is the gateway's ordinary work, at DEBUG (refused).
A read-only state read of ref (Kernel.stateAt, Kernel.trace) would replay more than limit streams of its log: it is refused before the stream past limit is folded, so a read of a long history costs at most limit streams and never holds the history in memory. The state the read asked for exists; it is only too far from the snapshot, or from version 1, to be replayed for a point read.
What a saga's handler declares it sends (me.ahoo.wow.api.annotation.Sends), by the commands' classes: those it derives (returns), those it schedules with SagaContext.schedule and those it calls with SagaContext.call. The compiler writes them into the handler's binding: what @Sends declares, else, for derives, what the handler's return type names. A command of a class none of the list's classes is, or is a subclass of, is undeclared: sending it fails the handling with an UndeclaredSendException.
A command a schedule sent (me.ahoo.wow.api.decide.Command.schedule) reached the kernel of ref longer before its slot's due time, by this kernel's clock (now), than the kernel waits for one: the firing node's clock runs that far ahead of this one. The command is not decided and the aggregate's queue is not held for it; the firing runner sends it again later, under the same request id, as after any technical failure.
Where the kernel keeps aggregates' states between commands, so a command does not replay the log.
The measured size of the states of each class, for a state cache bounded by bytes: the mean length of their JSON as the EventCodec that measures them writes it (the shared states and snapshots) and reads it (the snapshots loaded), over about its last WINDOW states.
The full types of the generated factories' dependencies, built without reflection: the compiler writes a parameterized parameter type as parameterized of its class and its type arguments, so Dependencies can tell StateViewCache<OrderStateView> from StateViewCache<PaymentStateView>. The types equal the JDK's of the same declaration, as ParameterizedType and WildcardType specify, so a host's container matches them.
A command's handling produced an event its function does not declare: a decide function or an after hook of the model of type produced event for command, outside the events its return type yields or its produces lists, or a lifecycle command's decide function another lifecycle event than its own. A bug in the model, not an outcome of the command: the command fails (wow.command.undeclared-event) and commits nothing.
A saga's handler subscription sent command, a command of a class its @Sends([member]) does not declare: a bug in the saga, not an outcome of the command, which no retry changes. The handling fails unrecoverable, so the aggregate parks at once, and the command is not sent.
An event of ref's stream at version that its model cannot read: its record name at revision fails to decode or to upgrade, as cause says. The kernel throws it from rebuilding a state, so the failure names the aggregate. It classifies as its cause does: a handler's @Retry lists and the failure classifiers see through it (FailureClassification).
The access policy (AccessPolicy) that decides who changes each aggregate type: the service's policy of it, the one its reads are decided by too, or none, and the default rule (ScopeAccess) decides. The host resolves the service's policies once, as the query side does; none by default.
Properties
Whether this command was derived by the server's own code rather than sent by a caller: a saga's, an @OnRejected compensation, a timer's, or one another context sent through its command topic. Such a command belongs to a chain, so it carries a Command.causation; admission gives a caller's none (it is its own root).
Functions
Builds an AggregateModel of state S for the aggregate name of bounded context context.
Builds an AggregateModel of state stateType for the aggregate name of bounded context context.
The context an @OnCommitted handler gets for committed: its execution is (handler, aggregate, version) of the commit whose saga execution derived the command, and the commands it derives are ExecutionReceiptContext's, deterministic per committed command; it takes its ids from ids.
The context an @OnCommitted handler gets for committed, as committedContextOf gives it, whose commands without a ref go to the aggregate type commandTypes assigns their class, and whose calls go through calls.
The context a handler of kind gets for the execution of event by the subscription subscription: its ExecutionId is (subscription, aggregate, version); a saga's takes its ids from ids, names the commands it schedules by commandTypes, makes its synchronous calls through calls and sends what sends declares; every handler reads through queries.
What an annotated command function returned, as a Decision: the conversion code that wow-compiler generates calls, so annotated functions keep returning what they return in 9.x.
Calls handle once for each event of stream that is a type, in their order, with the StateTypedEvent of that event and context seen as that call (invocationOf): its invocationKey names the event, while everything else, the ids a saga's commands take included, is the stream's context, so the n-th command the calls derive is the same request every time the stream is handled again. What each call returns, in order. The generated bindings call it, as they call requestsOf.
The context an @OnRejected handler gets for rejected: its execution is (handler, aggregate, version) of the commit whose saga execution derived the command, and the commands it derives are ExecutionReceiptContext's, deterministic per rejected command; it takes its ids from ids.
The context an @OnRejected handler gets for rejected, as rejectionContextOf gives it, whose commands without a ref go to the aggregate type commandTypes assigns their class, and whose calls go through calls.
The command requests a saga's handler returned: nothing (null, Unit, an empty Mono), one CommandRequest, or several, as an Iterable (such as the list a Flux was collected into), a Sequence or a Flow, collected in order. Anything else is a handler that does not return command requests: an InvalidDerivedRequestException.