matty-matt
matty-matt

Reputation: 47

Axon implicitly instantiate another aggregate using paramless constructor

I'm just wondering why Axon implicitly instantiate another aggregate. This behavior causes multiple event handling and I don't think this overhead is expected. Having this endpoint:

@PostMapping("ship")
public void shipOrder(@RequestBody Product product) {
        String orderId = UUID.randomUUID().toString();
        commandGateway.sendAndWait(new PlaceOrderCommand(orderId, product.getName()));
        commandGateway.sendAndWait(new ConfirmOrderCommand(orderId));
}

and following aggregate:

@Aggregate
public class Order {

    @AggregateIdentifier
    private String orderId;
    private boolean orderConfirmed;

    @CommandHandler
    public Order(PlaceOrderCommand command) {
        System.out.println("Calling COMMAND constructor");
        apply(new OrderPlacedEvent(command.getOrderId(), command.getProduct()));
    }

    protected Order() {
        System.out.println("Calling PARAMLESS constructor");
    }

    @CommandHandler
    public void handle(ConfirmOrderCommand command) {
        apply(new OrderConfirmedEvent(command.getOrderId()));
    }

    @EventSourcingHandler
    public void on(OrderPlacedEvent event) {
        System.out.println(">>>>>> Handling OrderPlacedEvent: " + this);
        this.orderId = event.getOrderId();
        orderConfirmed = false;
    }

    @EventSourcingHandler
    public void on(OrderConfirmedEvent event) {
        System.out.println(">>>>>> Handling OrderConfirmedEvent: " + this);
        orderConfirmed = true;
    }
}

After calling endpoint once I'm getting this log:

Calling COMMAND constructor
>>>>>> Handling OrderPlacedEvent: Order@3eecb9e2
Calling PARAMLESS constructor
>>>>>> Handling OrderPlacedEvent: Order@cd10277
>>>>>> Handling OrderConfirmedEvent: Order@cd10277

As you can see OrderPlacedEvent is called twice, along with constructor without parameters. Anyone know why I'm experiencing following behavior?

Upvotes: 0

Views: 331

Answers (1)

ViVeTech
ViVeTech

Reputation: 141

That behaviour is correct and expected when you use Event Sourcing. In Event Sourcing, whenever you send a command to an aggregate, it will first load all previous events to hydrate the aggregate and determine it's current state. These event are your source of thruth. The current state of the aggregate is, aside from some exceptions, not stored.

As such, in general you should make sure you only use your EventSourcingHandler in your aggregate to populate its state.

Note that once a system grows a lot, an aggregate could potentially have a large number of events that will need to be read. Should this occurs, there is some optimization you can do, by storing a snapshot of your aggregate (it's current state) after every n events. This way you won't have to load more than n events.

Upvotes: 1

Related Questions