CommandGatewayinterface and the
DefaultCommandGatewayimplementation 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.
RetryScheduleris 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.
IntervalRetrySchedulerwill retry a given command at set intervals until it succeeds,
ExponentialBackOffIntervalRetrySchedulerretries failed commands with an exponential back-off interval until
CommandDispatchInterceptors allow modification of
CommandMessages prior to dispatching them to the Command Bus. In contrast to
CommandDispatchInterceptors 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.
CommandCallbackcan be provided to the Command Gateway upon a regular
send, specifying what to do with the command handling result. It works with the
CommandResultMessageclasses, thus allowing for some generic behavior for all Commands sent through this gateway regardless of their type.
@MetaDataValuewill have their value assigned to the metadata field with the identifier passed as annotation parameter
MetaDatawill be merged with the
CommandCallbackwill have their
onResult(CommandMessage<? extends C>, CommandResultMessage<? extends R>)invoked after the command has been handled. Although the
CommandCallbackprovides 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
CommandCallbackinstances, which all will be invoked in order.
voidreturn 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.
CompletableFuturewill cause the method to return immediately.
CompletableFutureinstance returned from the method.
ClassCastExceptionif the types do not match).
CommandExecutionException, which is a
nullfrom the method.
TimeoutExceptionis thrown instead.
InterruptedExceptionon the method, this behavior is changed to throw that exception instead.
@MetaDataValueannotation on a parameter will have the value of that parameter added as metadata value.
@Timeoutwill block at most the indicated amount of time.
@Timeoutwill cause all methods declared in that class to block at most the indicated amount of time, unless they are annotated with their own
@Timeoutannotation or specify timeout parameters.
CommandBuscan be found here. Several flavors of the command bus, with differing characteristics, exist within the framework.
SimpleCommandBusis, 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.
SimpleCommandBusallows interceptors to be configured.
CommandDispatchInterceptors are invoked when a command is dispatched on the command bus. The
CommandHandlerInterceptors are invoked before the actual command handler method is, allowing you to do modify or block the command. See Command Interceptors for more information.
AsynchronousCommandBusimplementation executes commands asynchronously from the thread that dispatches them. It uses an
Executorto perform the actual handling logic on a different Thread.
AsynchronousCommandBususes 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.
Executorinstance may be provided to configure a different threading strategy.
AsynchronousCommandBusshould 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
Executorinstance, if it implements the
SimpleCommandBushas reasonable performance characteristics. The fact that the
SimpleCommandBusneeds locking to prevent multiple threads from concurrently accessing the same aggregate causes processing overhead and lock contention.
DisruptorCommandBustakes 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
DisruptorCommandBususes 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.
DisruptorCommandBuseasily outperforms the
SimpleCommandBusby a factor of 4(!), there are a few limitations:
DisruptorCommandBusonly supports event sourced aggregates.
DisruptorCommandBuscannot guarantee that commands are processed in the order they were dispatched.
DisruptorConfigurationinstance, 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.
DisruptorCommandBusmay claim cores for itself, you can use the
BlockingWaitStrategyto allow other processes a fair share of CPU.
Executor- sets the Executor that provides the Threads for the
CachedThreadPoolthat provides threads from a thread group called
TransactionManager- defines the transaction manager that should ensure that the storage and publication of events are executed within a transaction.
InvokerInterceptors- defines the
CommandHandlerInterceptors that are to be used in the invocation process.
PublisherInterceptors- defines the
CommandHandlerInterceptors 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.
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.
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.
DisruptorCommandBuswill wrap all generated events in a
CommandBusimplementations, 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.
CommandBusimplementations is 100. The configuration changes slightly per distributed implementation and as such will be covered in those sections.
CommandMessageand 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
RoutingKeyannotation 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
UnresolvedRoutingKeyPolicy- the default fallback that will cause an exception to be thrown when the routing key cannot be resolved from the given
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.
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.
MetaDataRoutingStrategyare considered the full implementations to configure. The
STATIC_KEYare 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:
RoutingStrategycan also be provided when necessary. When we need to deviate from the default
AnnotationRoutingStrategy, we should configure it like so:
axon-spring-boot-starterdependency, Axon will automatically configure the
Disabling Axon ServerThere are two options to disable Axon Framework's default of using the
- 1.By excluding the
- 2.By setting
falsewhen Spring Boot is used.
AxonServerCommandBusis 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.
DistributedCommandBusrelies 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
DistributedCommandBusshould be given a command, based on a routing key calculated by the routing strategy.