CommandClient

interface CommandClient

Sends command objects to aggregates, wherever they are served: the same calls reach an aggregate of this service in process, without encoding the command, and one of a peer context, known from the contract its api jar carries, through that context's command topic, or over HTTP with the HTTP implementation.

Each call takes one CommandRequest: the command object, the aggregate it goes to (its id and, unless the command's class says, its type), and how it is sent. The tenant and scope are the caller's, or the target's a cross-scope caller names (CommandRequest.targetTenant, CommandRequest.targetScope); a target tenant that is the caller's own is the caller's, so a request built from a ref of the caller's tenant (CommandRequest.to(event.ref, command) in a saga) is an ordinary one. Shorthands send a command by its id alone (client.wait(command, id)).

A client sends as one caller (of); the host's client sends as an anonymous one until of gives it another. Commands have no trusted mode by design: a write always carries an accountable caller and goes through the authorizer, so a system or service sender passes its own service caller.

  • send answers once the command is accepted: durable for a peer's command, whose topic acknowledged it, within the request's timeout. A request whose wait plan waits for more fails before it is sent: wait answers with that plan's result.

  • wait answers with the result the request's wait plan (CommandRequest.wait) ends with, the server's default plan when it names none.

  • stream emits each result of that plan's hops as each is reached, the last one the result wait would answer with; collecting the flow sends the command.

send and wait answer only a result that succeeded, and map what a command is answered by the result's status, not by where it was refused (@ahoo-wang/wow-client's CommandClient maps it the same way):

  • a result that succeeded: returned;

  • a rejected result: a CommandRejectedException;

  • a problem whose result is rejected, an admission refusal (an unknown command, an invalid one, a forbidden caller): a CommandRejectedException;

  • a result of a status this client does not know, a newer peer's: a WowProblemException wow.command.failed, not retryable;

  • any other problem, refused before admission (a body that does not parse), a technical failure (a busy or closing node, a store or a broker that is down, a wait that timed out) or a failed result: a WowProblemException, with its result when the peer sent one, and what a retry may do (WowProblemException.retry).

stream emits every result, whatever its status. A request whose aggregate type the client cannot derive from its command's class fails before anything is sent.

Functions

Link copied to clipboard
abstract fun of(caller: Caller): CommandClient

This client sending as caller.

Link copied to clipboard
abstract suspend fun send(request: CommandRequest<*>): CommandResult

Sends request, and answers once its command is accepted, whatever its wait plan.

Link copied to clipboard
suspend fun CommandClient.send(command: Any, id: String? = null): CommandResult

Sends command to the aggregate id names, its type derived from its class (CommandClient.send).

Link copied to clipboard
abstract fun stream(request: CommandRequest<*>): Flow<CommandResult>

The results of request's wait, sent when the flow is collected, in order.

Link copied to clipboard
fun CommandClient.stream(command: Any, id: String? = null): Flow<CommandResult>

The results of command sent to the aggregate id names (CommandClient.stream).

Link copied to clipboard
abstract suspend fun wait(request: CommandRequest<*>): CommandResult

Sends request, and answers with the result its wait plan ends with.

Link copied to clipboard
suspend fun CommandClient.wait(command: Any, id: String? = null): CommandResult

Sends command to the aggregate id names, and waits for its result (CommandClient.wait).