I'm using oracle database as event store and Subscribing Event Processor, when an exception is thrown in one of the event handlers, I want the events to be rolled back, but that does not happen.
Here's where I have looked
Axon FrameWork: How to rollback in the domain_event_entry table
Spring boot Axon complete rollback
Axon 3-Spring Boot Transaction Management
and of course the docs
My setup (axon 4.9 and Spring)
@Configuration
public class AxonConfig {
// omitting other configuration methods...
public void configureProcessorDefault(EventProcessingConfigurer processingConfigurer) {
processingConfigurer.usingSubscribingEventProcessors();
processingConfigurer.registerDefaultListenerInvocationErrorHandler(configuration -> PropagatingErrorHandler.INSTANCE);
}
@Bean
public CommandBus commandBus(MeterRegistry meterRegistry) {
TransactionManager transactionManager = springTransactionManager();
SimpleCommandBus commandBus = SimpleCommandBus
.builder()
.transactionManager(transactionManager)
.rollbackConfiguration(RollbackConfigurationType.ANY_THROWABLE)
.build();
commandBus.registerHandlerInterceptor(new TransactionManagingInterceptor < > (transactionManager));
return commandBus;
}
@Bean public EventStorageEngine eventStorageEngine() {
return JdbcEventStorageEngine
.builder()
.snapshotSerializer(xStreamSerializer)
.upcasterChain(upcasterChain)
.persistenceExceptionResolver(persistenceExceptionResolver())
.eventSerializer(eventSerializer)
.connectionProvider(new SpringDataSourceConnectionProvider(dataSource))
.transactionManager(springTransactionManager())
.build();
}
}
public class Aggregate {
@CommandHandler
public void handle(MyCommand command,
UnitOfWork parent) {
apply(new CommandCalled());
}
public class ProjectionHandler {
@EventHandler
public void on(CommandCalled event,
UnitOfWork child) {
throw new RuntimeException();
}
commandGateway.sendAndWait(new MyCommand());
one observation is that the parent of UnitOfWork in the event handler is the one in the command handler, I've tried CurrentUnitOfWork.get().rollback() but it didnt work
1 Answer 1
To be frank, I would expect that an Axon Framework application that:
- Does not distributed any messages,
- uses a
SimpleCommandBus, ensuring no additional thread pools are used anywhere for command handling, and - forces the
EventProcessorto be aSubscribingEventProcessorinstance, would land in your "desired" scenario.
I am putting "desired" between quotes, as it means you're running fully synchronous. Although achievable with the Axon Framework, it goes a little beyond the benefits of a message-driven system. I am actually explaining that somewhat in the third link you've shared (more specifically, this comment).
Nonetheless, if it truly is what you desire, I am kind of surprised that the described setup doesn't work for you, Omar.
So, could you perchance explain how the configureProcessorDefault method is invoked in your context?
On top of that, it would be good to know if you have a token_entry table in your database. And, if so, if that entry contains any rows at all. If it does, it would be beneficial to share that information as well.
The reason for going in this angle with questioning is that I expect your event processor is potentially still backed by a TrackingEventProcessor instead of a SubscribingEventProcessor.
To conclude, I do want to stress that the synchronous solution with Axon Framework is, in most cases, not recommended. You lose the flexibility that an asynchronous system provides. Axon Framework 5 will move even further in that asynchronous direction, actually.