@SagaEventHandler without payload type sometimes doesn't trigger

Hi,

We ran into a strange issue where Saga’s wouldn’t start. Our handler has both @StartSaga and @SagaEventHandler, and the first parameter is the payload, however in one of our environments (prod) the saga (usually) didn’t start, and the event didn’t complete processing (checked using MessageMonitor.Callback). After adding the payload type to the @SagaEventHandler, it works.

Is this a know issue, or are we missing something?

Thanks
Niel

I can reliably reproduce this. After triggering the saga, this exception is thrown:
2017-08-31 19:46:38.243 ERROR 1 --- [SagaProcessor-0] o.a.e.TrackingEventProcessor : Processing loop ended due to uncaught exception. Processor pausing. java.lang.StackOverflowError: null at org.jboss.logging.Logger.logf(Logger.java:2397) at org.jboss.logging.DelegatingBasicLogger.tracef(DelegatingBasicLogger.java:124) at org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl.close(ResourceRegistryStandardImpl.java:148) at org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl.releaseResources(ResourceRegistryStandardImpl.java:292) at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.afterTransaction(AbstractLogicalConnectionImplementor.java:55) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.afterTransaction(LogicalConnectionManagedImpl.java:149) at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.afterCompletion(LogicalConnectionManagedImpl.java:260) at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.rollback(AbstractLogicalConnectionImplementor.java:122) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.rollback(JdbcResourceLocalTransactionCoordinatorImpl.java:239) at org.hibernate.engine.transaction.internal.TransactionImpl.rollback(TransactionImpl.java:100) at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:544) at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:853) at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:830) at org.axonframework.spring.messaging.unitofwork.SpringTransactionManager.rollbackTransaction(SpringTransactionManager.java:91) at org.axonframework.spring.messaging.unitofwork.SpringTransactionManager$1.rollback(SpringTransactionManager.java:68) at org.axonframework.common.transaction.TransactionManager.fetchInTransaction(TransactionManager.java:71) at org.axonframework.eventsourcing.eventstore.jpa.JpaEventStorageEngine.fetchTrackedEvents(JpaEventStorageEngine.java:149) at org.axonframework.eventsourcing.eventstore.BatchingEventStorageEngine.lambda$readEventData$1(BatchingEventStorageEngine.java:119) at org.axonframework.eventsourcing.eventstore.BatchingEventStorageEngine$EventStreamSpliterator.tryAdvance(BatchingEventStorageEngine.java:157) at java.util.stream.StreamSpliterators$WrappingSpliterator.lambda$initPartialTraversalState$0(StreamSpliterators.java:294) at java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.fillBuffer(StreamSpliterators.java:206) at java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.doAdvance(StreamSpliterators.java:161) at java.util.stream.StreamSpliterators$WrappingSpliterator.tryAdvance(StreamSpliterators.java:300) at java.util.Spliterators$1Adapter.hasNext(Spliterators.java:681) at org.axonframework.eventsourcing.eventstore.EmbeddedEventStore$EventConsumer.peekPrivateStream(EmbeddedEventStore.java:379) at org.axonframework.eventsourcing.eventstore.EmbeddedEventStore$EventConsumer.peek(EmbeddedEventStore.java:340) at org.axonframework.eventsourcing.eventstore.EmbeddedEventStore$EventConsumer.peekPrivateStream(EmbeddedEventStore.java:388) at org.axonframework.eventsourcing.eventstore.EmbeddedEventStore$EventConsumer.peek(EmbeddedEventStore.java:340) at org.axonframework.eventsourcing.eventstore.EmbeddedEventStore$EventConsumer.peekPrivateStream(EmbeddedEventStore.java:388) at org.axonframework.eventsourcing.eventstore.EmbeddedEventStore$EventConsumer.peek(EmbeddedEventStore.java:340) ... and many more of these ...

After this, sagas don’t trigger. When the app is restarted, those sagas get triggered. If there are no more sagas to process, I can repeat this. Start the app, trigger sagas, until seeing this exception, after which no more sagas will get triggered.

Cheers
Niel

What got omitted from the last post:

The “peek” stack keeps going until a stack overflow is thrown. After that sagas are no longer triggered. Restarting the app triggers the sagas, but the exception comes up again, stopping saga processing. The first saga is always triggered.

Cheers

Hi Niel,

there is an issue (https://github.com/AxonFramework/AxonFramework/issues/363) reported for this, but until now, it didn’t seem very reproducible. This may help in starting to understand what’s going on.

One suggestion there is that it is related to gaps. While gaps should be a very rare thing, in certain databases they are very common. This has to do with the way Hibernate generates sequences. It default to a single sequence generator used for all entities. A solution would be to configure a separate SequenceGenerator for the DomainEventEntry table, which can be done using the given configuration, which should be placed in a META-INF/orm.xml:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="[http://java.sun.com/xml/ns/persistence/orm](http://java.sun.com/xml/ns/persistence/orm)" version="2.0">
    <mapped-superclass class="org.axonframework.eventsourcing.eventstore.AbstractSequencedDomainEventEntry" access="FIELD">
        <attributes>
            <id name="globalIndex">
                <generated-value generator="domainEventGenerator" strategy="SEQUENCE"/>
            </id>
        </attributes>
    </mapped-superclass>
    <entity class="org.axonframework.eventsourcing.eventstore.jpa.DomainEventEntry" access="FIELD">
        <sequence-generator name="domainEventGenerator" sequence-name="domain_event_seq" allocation-size="1"/>
    </entity>
</entity-mappings>

Hope this relieves the issue, for now.
Cheers,

Allard