CommandGateway
is mentioned, as well as the CommandBus
in both a local and distributed environment.CommandGateway
interface and the DefaultCommandGateway
implementation provided by Axon. The command gateway provides a number of methods that allow you to send a command and wait for a result either synchronously, with a timeout or asynchronously.CommandGatewayFactory
. This allows you to define your application's interface using strong typing and declaring your own (checked) business exceptions. Axon will automatically generate an implementation for that interface at runtime.RetryScheduler
, CommandDispatchInterceptor
s, and CommandCallback
s.RetryScheduler
is capable of scheduling retries when command execution has failed. When a command fails due to an exception that is explicitly non-transient, no retries are done at all. Note that the retry scheduler is only invoked when a command fails due to a RuntimeException
. Checked exceptions are regarded as a "business exception" and will never trigger a retry.IntervalRetryScheduler
will retry a given command at set intervals until it succeeds,ExponentialBackOffIntervalRetryScheduler
retries failed commands with an exponential back-off interval untilCommandDispatchInterceptor
s allow modification of CommandMessage
s prior to dispatching them to the Command Bus. In contrast to CommandDispatchInterceptor
s configured on the Command Bus, these interceptors are only invoked when messages are sent through this Gateway. For example, these interceptors could be used to attach metadata to a command or perform validation.CommandCallback
can be provided to the Command Gateway upon a regular send
, specifying what to do with the command handling result. It works with the CommandMessage
and CommandResultMessage
classes, thus allowing for some generic behavior for all Commands sent through this gateway regardless of their type.@MetaDataValue
will have their value assigned to the metadata field with the identifier passed as annotation parameterMetaData
will be merged with the MetaData
on the CommandMessage
.CommandCallback
will have their onResult(CommandMessage<? extends C>, CommandResultMessage<? extends R>)
invoked after the command has been handled. Although the CommandCallback
provides a means to deal with the result of command handling, this is no impact on whether you can define a return type on the custom command gateway. In case both a callback and return type are defined, the invocations of the callback will always match with the return value (or exception). Lastly, know that you may pass in several CommandCallback
instances, which all will be invoked in order.long
(or int
) and TimeUnit
.void
return type will cause the method to return immediately, unless there are other indications on the method that one would want to wait, such as a timeout or declared exceptions.Future
, CompletionStage
and CompletableFuture
will cause the method to return immediately.CompletableFuture
instance returned from the method.ClassCastException
if the types do not match).CommandExecutionException
, which is a RuntimeException
.null
from the method.TimeoutException
.TimeoutException
is thrown instead.InterruptedException
on the method, this behavior is changed to throw that exception instead.@MetaDataValue
annotation on a parameter will have the value of that parameter added as metadata value.@Timeout
will block at most the indicated amount of time.@Timeout
will cause all methods declared in that class to block at most the indicated amount of time, unless they are annotated with their own @Timeout
annotation or specify timeout parameters.CommandBus
can be found here. Several flavors of the command bus, with differing characteristics, exist within the framework.SimpleCommandBus
is, as the name suggests, the simplest implementation. It does straightforward processing of commands in the thread that dispatches them. After a command is processed, the modified aggregate(s) are saved and generated events are published in that same thread. In most scenarios, such as web applications, this implementation will suit your needs.CommandBus
implementations, the SimpleCommandBus
allows interceptors to be configured. CommandDispatchInterceptor
s are invoked when a command is dispatched on the command bus. The CommandHandlerInterceptor
s are invoked before the actual command handler method is, allowing you to do modify or block the command. See Command Interceptors for more information.CommandBus
implementations.AsynchronousCommandBus
implementation executes commands asynchronously from the thread that dispatches them. It uses an Executor
to perform the actual handling logic on a different Thread.AsynchronousCommandBus
uses an unbounded cached thread pool. This means a thread is created when a command is dispatched. Threads that have finished processing a command are reused for new commands. Threads are stopped if they have not processed a command for 60 seconds.Executor
instance may be provided to configure a different threading strategy.AsynchronousCommandBus
should be shut down when stopping the application, to make sure any waiting threads are properly shut down. To shut down, call the shutdown()
method. This will also shutdown any provided Executor
instance, if it implements the ExecutorService
interface.SimpleCommandBus
has reasonable performance characteristics. The fact that the SimpleCommandBus
needs locking to prevent multiple threads from concurrently accessing the same aggregate causes processing overhead and lock contention.DisruptorCommandBus
takes a different approach to multithreaded processing. Instead of having multiple threads each doing the same process, there are multiple threads, each taking care of a piece of the process. The DisruptorCommandBus
uses the Disruptor, a small framework for concurrent programming, to achieve much better performance, by just taking a different approach to multi-threading. Instead of doing the processing in the calling thread, the tasks are handed off to two groups of threads, that each take care of a part of the processing. The first group of threads will execute the command handler, changing an aggregate's state. The second group will store and publish the events to the event store.DisruptorCommandBus
easily outperforms the SimpleCommandBus
by a factor of 4(!), there are a few limitations:DisruptorCommandBus
only supports event sourced aggregates.createRepository(AggregateFactory)
.DisruptorCommandBus
cannot guarantee that commands are processed in the order they were dispatched.DisruptorCommandBus
instance, you need an EventStore
. This component is explained in the Event Bus and Event Store section.DisruptorConfiguration
instance, which allows you to tweak the configuration to optimize performance for your specific environment:Buffer size
- the number of slots on the ring buffer to register incoming commands.ProducerType
- indicates whether the entries are produced by a single thread, or multiple. Defaults to multiple.WaitStrategy
- the strategy to use when the processor threads (the three threads taking care of the actual processing) need to wait for each other.DisruptorCommandBus
may claim cores for itself, you can use the BusySpinWaitStrategy
.YieldingWaitStrategy
.SleepingWaitStrategy
and BlockingWaitStrategy
to allow other processes a fair share of CPU.BlockingWaitStrategy
.Executor
- sets the Executor that provides the Threads for the DisruptorCommandBus
.DisruptorCommandBus
.CachedThreadPool
that provides threads from a thread group called "DisruptorCommandBus"
.TransactionManager
- defines the transaction manager that should ensure that the storage and publication of events are executed within a transaction.InvokerInterceptors
- defines the CommandHandlerInterceptor
s that are to be used in the invocation process.PublisherInterceptors
- defines the CommandHandlerInterceptor
s that are to be used in the publication process.RollbackConfiguration
- defines on which Exceptions a Unit of Work should be rolled back.RescheduleCommandsOnCorruptState
- indicates whether Commands that have been executed against an Aggregate that has been corrupted (e.g. because a Unit of Work was rolled back) should be rescheduled.false
the callback's onFailure()
method will be invoked.true
(the default), the command will be rescheduled instead.CoolingDownPeriod
- sets the number of seconds to wait to make sure all commands are processed.1000
(1 second).Cache
- sets the cache that stores aggregate instances that have been reconstructed from the Event Store.InvokerThreadCount
- the number of threads to assign to the invocation of command handlers.PublisherThreadCount
- the number of threads to use to publish events.SerializerThreadCount
- the number of threads to use to pre-serialize events.1
, but is ignored if no serializer is configured.Serializer
- the serializer to perform pre-serialization with.DisruptorCommandBus
will wrap all generated events in a SerializationAware
message.CommandBus
implementations, the distributed command buses do not invoke any handlers at all. All they do is form a "bridge" between command bus implementations on different JVM's, delegating any received commands to the so-called local segment.SimpleCommandBus
. You can configure the local segment to be any of the other local command buses too, like the AsynchronousCommandBus
and DisruptorCommandBus
. The details of how to configure the local segment are shown in the implementation sections.CommandBus
implementations is 100. The configuration changes slightly per distributed implementation and as such will be covered in those sections.RoutingStrategy
.RoutingStrategy
receives a CommandMessage
and based on the message returns the routing key to use. Two commands with the same routing key will always be routed to the same segment, as long as there is no topology change in the distributed set-up.RoutingStrategy
. Three of these are intended to be fallback solutions, in case the routing key cannot be resolved:AnnotationRoutingStrategy
- the default routing strategy expects the TargetAggregateIdentifier
or RoutingKey
annotation to be present on a field inside the command class. The annotated field or getter is searched, and the contents will be returned as the routing key for that command.MetaDataRoutingStrategy
- uses a property defined during creation of this strategy to fetch the routing key from the CommandMessage
's MetaData
.ERROR
UnresolvedRoutingKeyPolicy
- the default fallback that will cause an exception to be thrown when the routing key cannot be resolved from the given CommandMessage
.RANDOM_KEY
UnresolvedRoutingKeyPolicy
- will return a random value when a routing key cannot be resolved from the CommandMessage
. This means that those commands will be routed to a random segment of the command bus.STATIC_KEY
UnresolvedRoutingKeyPolicy
- will return a static key (named "unresolved") for unresolved routing keys. This policy routes all commands to the same segment, as long as the configuration of segments does not change.AnnotationRoutingStrategy
and MetaDataRoutingStrategy
are considered the full implementations to configure. The ERROR
, RANDOM_KEY
and STATIC_KEY
are fallback routing strategies that should be configured on the annotation or meta-data implementations. To get a grasp how these are constructed, consider the following sample:RoutingStrategy
can also be provided when necessary. When we need to deviate from the default AnnotationRoutingStrategy
, we should configure it like so:AxonServerCommandBus
is the default distributed CommandBus
implementation that is set by the framework. It connects to AxonServer, with which it can send and receive commands.axon-spring-boot-starter
dependency, Axon will automatically configure the AxonServerCommandBus
:Disabling Axon ServerThere are two options to disable Axon Framework's default of using theAxonServerCommandBus
:
1.By excluding theaxon-server-connector
dependency. 2.By settingaxon.server.enabled
tofalse
when Spring Boot is used.When doing any of these, Axon will fallback to the undistributedSimpleCommandBus
, unless configured otherwise.
AxonServerCommandBus
is defined through the CommandLoadFactorProvider
. This interface allows us to distinguish between commands to, for example, use a different load factor per command message. This might be useful if some commands are routed more often towards one instance in favour of the other.AxonServerCommandBus
is the DistributedCommandBus
. Each instance of the DistributedCommandBus
on each JVM is referred to as a "Segment".DistributedCommandBus
relies on two components:CommandBusConnector
- implements the communication protocol between the JVM's to send the command over the wire and to receive the response.CommandRouter
- chooses the destination for each incoming command. It defines which segment of the DistributedCommandBus
should be given a command, based on a routing key calculated by the routing strategy.DistributedCommandBus
:DistributedCommandBus
.