MessageHandlerInvocationException on a different event than initial command

Hi,

I try to figure the cause of this exception. On an existing domain object, I send DeleteOrderItemCommand to command gateway but it throws MessageHandlerInvocationException stating the event type is different. I check the commandhandler in aggregate and it is correct. It should apply OrderItemDeleteEvent, not ItemAddEventEvent, to event queue. If I create a new domain object, this exception won’t happen.

Command ‘com.x.orderservice.coreapi.DeleteOrderItemCommand’ resulted in org.axonframework.messaging.annotation.MessageHandlerInvocationException(Error handling event of type [class com.x.orderservice.coreapi.ItemAddedEvent] in aggregate)

@CommandHandler
protected void on(DeleteOrderItemCommand command) {
    OrderItemDeletedEvent event = new OrderItemDeletedEvent(command.getOrderEventId(),command.getOrderItemId(),command.getAccountId(), command.getOrderItemList());
    apply(event);
}

I begin to think (not sure) it is caused by the missing events happened to these existing domain object. A new command/event is added to the domain object recently. The new event should execute after ItemAddEventEvent. If this is the case, how can I make the existing domain objects (before new command/event was added) to work again? Any suggestion are appreciated.

Thanks.

Wai

Hi Wai,

Did you verify that the command handler snippet you have sent is actually called by adding for example logging/break points?
Is the ItemAddedEvent also an event which is applied in that same aggregate?
I’m just guessing here because I’m unsure of the nature of your aggregate, but maybe something during the initialization of the aggregate fails, making it so that you never even hit the command handler in your snippet of code.

Maybe some extra info from your side might help explain this issue.

Cheers,

Steven

Steven,

No, the command handler did not called. ItemAddedEvent is one of the events in the same aggregate. The new “update order” event should be called right after ItemAddedEvent but the existing domain object was created before the new “update order” event even exists. If Axon try to re-initialize and replay all events, then new “update order” event will be missing for these old domain objects. If this is the case, any way to have Axon skips the new event for these old domain objects during aggregate initialization?

Thanks.

Wai

Hi Wai,

So, if I understand correctly you’ve updated the events by adding an UpdateItemEvent in a later version, which is now a mandatory event.
So, aggregate’s which have been created prior to this change wont have the UpdateItemEvent, correct?
I can think of several solutions:

  • If this is on a test/dev environment, adjusting the events/event order shouldn’t bother you, so I’d clean your database.
  • Without knowing if this is possible with your aggregate or not, but you could make the procedure less strict just so that the UpdateOrderEvent isn’t mandatory.
  • The I’d say cleanest solution is to create an upcaster, which based on an old ItemAddedEvent returns the ItemAddedEvent and the new UpdateItemEvent.

Hoping this helps.

Cheers,
Steven

Thanks for your suggestions

Yes, for dev environment, I just drop schema and start over. For shared testing environment, I try to make UpdateOrderEvent isn’t mandatory but I can’t find any reference on how to do that. Do you have any information on that?

For long term and future production needs, I probably need to learn how to do upcasting events.

Wai.

Hi Wai,

For an acceptance environment I’d take the stance not to remove your old events, so you can ensure that the upcaster you’d eventually implement actually work.
For test environment I’d either pick your development environment strategy, thus dropping the database, or a similar approach as to an acceptance environment, thus actually writing upcasters.
If you complete setup is not in production yet however, I wouldn’t be to afraid to clean your event store.

To answer the question you pose, I’m not sure how you made the UpdateOrderEvent mandatory.
Is it an event you created your self? Could you maybe send a snippet of your aggregate showing the command and event handlers around the commands/events we’ve been discussing?

Hope this helps.

Cheers,
Steven

Regarding how I make UpdateOrderEvent mandatory, originally, the event flow is CreateOrder Command/Event to create an order, then AddOrderItem Command/Event to add item the order. Later on, UpdateOrder Command/Event is added right after CreateOrder Command/Event is completed in event handler to update order with new data from third party service.

Before

CreateOrderEvent --> AddOrderItemEvent

After

CreateOrderEvent --> call third party service --> UpdateOrderEvent --> AddOrderItemEvent

In your previous message, you mention about “you could make the procedure less strict just so that the UpdateOrderEvent isn’t mandatory.”. I assume there is a way to skip UpdateOrder event during aggregate initialization.

Thank you.

Wai

Hi Wai,

To be fair, I’m still unsure why your aggregate doesn’t want to event source because an aggregate misses a certain event in it’s event stream.
To me that suggests you’ve set up your Aggregate to require that event, hence the question I posed for you to share a snippet of code.

And, as far as I know there is no way to skip events when an aggregate is event sourced other than not having a @EventSourcingHandler for that event.
Axon will load in all the events tied to an aggregate based on the AggregateIdentifier and selects an @EventSourcingHandler function from the Aggregate.
If there is none, it should just ignore that event.

So in your scenario, when you’re event sourcing an old aggregate which doesn’t have the UpdateOrderEvent but your aggregate still breaks during this process, this leads me to think you have an @EventSourcingHandler for the UpdateOrderEvent which does something important which makes it so that the later process breaks.

Cheers,
Steven