Axon + Spring boot = problems (race condition on Axon initialization?)

Hi everyone.

I’m creating a POC based on Axon framework. It’s been a rough start, but thanks to couple debugger sessions I’m finally able to send command/event for one aggregate.

But just after moving forward and trying to do anything more useful I run yet on another bunch of problems.

I would appreciate if more experienced colleagues could please shed more light on this…

Axon: 4.2
Spring Boot 2.1.6/2.2.0

Setup: Boot-autowired JPA-driven stores + event source store + Disruptor command like this:

(…) = abbreviation for clarity in post below

@Bean
public CommandBus customCommandBus(TransactionManager txManager, AxonConfiguration axonConfiguration) {
    DisruptorCommandBus commandBus =
        DisruptorCommandBus.builder()
            .transactionManager(txManager)
            .messageMonitor(axonConfiguration.messageMonitor(DisruptorCommandBus.class, "commandBus"))
            .build();
    commandBus.registerHandlerInterceptor(new CorrelationDataInterceptor<>(axonConfiguration.correlationDataProviders()));
    commandBus.registerHandlerInterceptor(new LoggingInterceptor());
    commandBus.registerDispatchInterceptor(new LoggingInterceptor());
    return commandBus;
}

Problem 1:

I have one @Aggregate: Engine. Flow is as follow: send CreateEngineCommand(“a”) to @CommandHandler constructor, then work with created Aggregate and send some more commands like AcceptItemCommand

When I execute this flow from a Spring @Component public class AxonTester implements CommandLineRunner run(), everything works properly and events are stored in the evenstorage
But when I try to do initialization of this aggregate (so sending CreateEngineCommand) from another @Component during application startup:

@Component
public class AxonIOFactory
{

Hi Derek,

here is a quick explanation of the behavior you’re seeing.
Problem 1:
This is a typical Spring startup timing issue. If you send the command before CommandBus registrations have gone out, then you’re guaranteed to get this error. Instead, you should listen for Spring’s ApplicationStartedEvent (or ContextRefreshedEvent). That way, you are sure that all lifecycles for beans have been completed.

Problem 2:
In general, interaction should be done by sending commands. If you really do need to access a Repository directly, you must do so in the scope of a Unit of Work.
For example:
DefaultUnitOfWork.startAndGet().executeWithResult(() -> {… whatever you want to do …});

The DisruptorCommandBus is a special case. It uses a specialized implementation of the Repository, which isn’t designed for direct access at all. In that case, you’d have to send commands to the DisruptorCommandBus to have them executed.

Problem 3:
Yes, these messages are normal. We’re currently working on improving the interaction between Spring and Axon Configuration, especially with regards to timing.

Hope this clarifies things.
Kind regards,

twitter-icon_128x128.png

Hi Allard,

All clear now, thank you :).

Best regards,
Darek