Command chain with sendAndWait

I’m facing an issue related to the order of events when handling commands in my Axon-based Spring Boot application, and I’m using a command chain for executing the commands.

Here is the command handler I’m working with:


    @CommandHandler
    @CreationPolicy(AggregateCreationPolicy.CREATE_IF_MISSING)
    public void handle(InitializeProduct cmd, CommandGateway commandGateway) {
        final EnrichProduct enrichProduct = EnrichProduct.builder()
                .id(cmd.getId())
                .isDesignated(cmd.getIsDesignated())
                .relationShip(cmd.getRelationShip())
                .atTaxCharge(cmd.getAtTaxCharge())
                .build();

        commandGateway.sendAndWait(enrichProduct);  // Trying to ensure ProductEnriched is triggered first

        final ProductInitialized evt = ProductInitialized.builder()
                .id(cmd.getId())
                .statusDate(LocalDate.now())
                .build();

        AggregateLifecycle.apply(evt);
    }

    @CommandHandler
    public void handle(EnrichProduct cmd) {
        final ProductEnriched evt = ProductEnriched.builder()
                .id(cmd.getId())
                .isDesignated(cmd.getIsDesignated())
                .relationShip(cmd.getRelationShip())
                .atTaxCharge(cmd.getAtTaxCharge())
                .build();

        AggregateLifecycle.apply(evt);
    }

I want the ProductEnriched event to be triggered first, but with the current setup, the ProductInitialized event is applied first. When I use commandGateway.sendAndWait to ensure that ProductEnriched is sent before ProductInitialized, I encounter the following error:

An exception has occurred during command execution: org.axonframework.commandhandling.CommandExecutionException: An exception has occurred during command execution
Caused by: AxonServerRemoteCommandHandlingException{message=An exception was thrown by the remote message handling component: An exception has occurred during command execution
Caused by Failed to acquire lock for identifier(e5f95417-3d2b-444c-90df-e0849f962801), maximum attempts exceeded (6000), errorCode='AXONIQ-4002}

I want the ProductEnriched event to be triggered first, before ProductInitialized. However, I am facing issues when trying to use sendAndWait. I am not sure if I am missing something in the event processing sequence, or if there is a better way to ensure the order of event handling.

You should not call the command gateway from the command handler, unless for some advanced patterns like an orchestrator. And never to the same aggregate instance, as that will fail with the error you encountered. Can’t you just apply both events, one after the other?

1 Like

I second @gklijs his reply, @Aymen_Kanzari. I would not recommend to use a CommandBus or CommandGateway from within an Aggregate Command handler. Given that the shared block of code has the @CreationPolicy annotation, I am certain this is from within an aggregate.

Axon will lock an aggregate when a command is being handled. This is done to protect the so-called consistency boundary, as intended for aggregates. Hence, by dispatching a command from within an aggregate command handler, you may (1) lock multiple aggregates in a row and/or (2) cause a cyclic “dependency.”

As Gerard already suggests, if the ProductEnriched event can be published by the aggregate right away, it would make sense to directly invoke the EnrichtProduct command handler instead of using the command bus.