Configure EventHandlerInterceptor on EventSourcingHandler

Is it possible to have a custom EventHandlerInterceptor that is called as part of the interceptor chain just before the EventSourcingHandler of an aggregate is called? Similar to how @CommandHandlerInterceptor works on aggregates.

I want the handler to be called when I do an AggregateLifecycle.apply(event) from inside the aggregate and when the aggregate is loaded from the eventstore. The handler would to its stuff and then call interceptorchan.proceed().

The reason for having such an interceptor is to move common logic from each @EventSourcingHandler method in the aggregate to a central location. Thus ensuring that the code is always executed and not left out by accident when a new @EventSourcingHandler is added to the aggregate.

So, intercepting the event sourcing handler invocation is something which (at the moment) is not supported. Not through registering a MessageHandlerInterceptor bean, but also not through means of a @CommandHandlerInterceptor-like solution.

I do understand the question though, as cross cutting concerns on @EventSourcingHandler annotated methods also makes sense. Would you be able to specify what you actually want to do on every event sourcing handler annotated method?

Meanwhile, another solution to introduce a cross cutting concern is by adding what’s called a Handler Enhancer. It might not entirely cover your use case though, so knowing what you intend to add to every event sourcing handler would be good to know.

Hope this already helps you out to some extent @frehen!

Cheers,
Steven

I have implemented a general pattern for handling idempotency, where each command has a unique command id (at least per aggregate). This cmdId is also present in the events since I’m using eventsourcing.

When an aggregate handles a command it adds the cmdId to an internal Set of ids. So if the command comes again the CommandHandler skips the command. Since I’m using eventsourcing the actual implementation where the command id is added to the internal Set is in the eventsourcehandler. This I’ll have to do for each handler. If one is forgotten, it will not work for that command.

For checking if a command should be executed, I use a general commandhandler like:

@CommandHandlerInterceptor
fun intercept(cmd: SakCommand, chain: InterceptorChain, eventStore: EventStore, unitOfWork: UnitOfWork<out Message<*>>): Any {
    if (!processedCommands.contains(cmd.cmdId)) {
        val result = chain.proceed()
        if (result != null) throw IllegalArgumentException("Expected CommandHandler of command ${cmd::class} not to have a return value")
        if (!processedCommands.contains(cmd.cmdId)) throw IllegalStateException("Expected CommandHandler of command ${cmd::class} to have added command id to the aggregates set of processed commands")
    }
    return null
}

As you can see, I have added a test to catch if the commandId was not added when a command is processed.

Nice to know that the feature is not supported. Then I can stop looking and it confirms my understanding.

Thanks for the response
Henrik

1 Like