-
Notifications
You must be signed in to change notification settings - Fork 8
Description
Trying out AF5 university demo Spring Boot branch and I've tried to update it to use a JPA data store for the projector/read model with correspondent TokenStore, just against a H2 database, but get errors even with the most basic setup I could configure.
Not sure if this is how I'm setting it up and needs an exmaple/documentation on how to configure AxonServer with JPA read models or a possible bug, so adding it here just in case it is more than a picnic error.
I get the following exception thrown
java.util.concurrent.CompletionException: java.lang.IllegalStateException: No value for key [HikariDataSource (HikariPool-1)] bound to thread
at java.base/java.util.concurrent.CompletableFuture.encodeRelay(CompletableFuture.java:368) ~[na:na]
My expectation was that just plugging JPA would work, but not sure this is correct.
My modified UniversitySpringBootAxonApplication to setup the TokenStore (based on the AutoJPAConfiguration spring auto config)
package io.axoniq.demo.university;
import io.axoniq.demo.university.faculty.write.classic.EnrollStudent;
import io.axoniq.demo.university.faculty.write.createcourse.CreateCourse;
import io.axoniq.demo.university.faculty.write.renamecourse.RenameCourse;
import io.axoniq.demo.university.shared.application.notifier.NotificationService;
import io.axoniq.demo.university.shared.ids.CourseId;
import io.axoniq.demo.university.shared.ids.StudentId;
import io.axoniq.demo.university.shared.infrastructure.notifier.LoggingNotificationService;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.axonframework.common.jpa.EntityManagerProvider;
import org.axonframework.common.transaction.TransactionManager;
import org.axonframework.configuration.ComponentRegistry;
import org.axonframework.eventhandling.processors.streaming.token.store.TokenStore;
import org.axonframework.eventhandling.processors.streaming.token.store.inmemory.InMemoryTokenStore;
import org.axonframework.eventhandling.processors.streaming.token.store.jpa.JpaTokenStore;
import org.axonframework.eventhandling.processors.streaming.token.store.jpa.JpaTokenStoreConfiguration;
import org.axonframework.extension.spring.config.SpringComponentRegistry;
import org.axonframework.extension.spring.messaging.unitofwork.SpringTransactionManager;
import org.axonframework.extension.springboot.TokenStoreProperties;
import org.axonframework.extension.springboot.util.RegisterDefaultEntities;
import org.axonframework.extension.springboot.util.jpa.ContainerManagedEntityManagerProvider;
import org.axonframework.serialization.json.JacksonConverter;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.logging.Level;
import java.util.logging.Logger;
@SpringBootApplication
@EnableConfigurationProperties(TokenStoreProperties.class)
@RegisterDefaultEntities(packages = {
"org.axonframework.eventhandling.processors.streaming.token.store.jpa"
})
public class UniversitySpringBootAxonApplication {
public static void main(String[] args) {
SpringApplication.run(UniversitySpringBootAxonApplication.class, args);
}
@Bean
public NotificationService notificationService() {
return new LoggingNotificationService();
}
// @Bean
// public TokenStore tokenStore() {
// return new InMemoryTokenStore();
// }
@Bean
EntityManagerProvider entityManagerProvider() {
return new ContainerManagedEntityManagerProvider();
}
@Bean
TokenStore tokenStore(
EntityManagerProvider entityManagerProvider,
TokenStoreProperties tokenStoreProperties,
ObjectMapper defaultAxonObjectMapper) {
var config = JpaTokenStoreConfiguration.DEFAULT.claimTimeout(tokenStoreProperties.getClaimTimeout());
var converter = new JacksonConverter(defaultAxonObjectMapper);
JpaTokenStore tokenStore = new JpaTokenStore(entityManagerProvider, converter, config);
return tokenStore;
}
@Bean
TransactionManager axonTransactionManager(PlatformTransactionManager transactionManager) {
return new SpringTransactionManager(transactionManager);
}
@Component
static class MySampleApplicationRunner implements ApplicationRunner {
private final Logger logger = Logger.getLogger(this.getClass().getName());
private final ComponentRegistry componentRegistry;
MySampleApplicationRunner(ComponentRegistry componentRegistry) {
this.componentRegistry = componentRegistry;
}
@Override
public void run(ApplicationArguments args) throws Exception {
try {
var courseId = CourseId.random();
var createCourse = new CreateCourse(courseId, "Event Sourcing in Practice", 3);
var renameCourse = new RenameCourse(courseId, "Advanced Event Sourcing");
var studentId = StudentId.random();
var enrollStudent = new EnrollStudent(studentId, "Kermit", "The Frog");
var commandGateway = ((SpringComponentRegistry) this.componentRegistry).configuration()
.getComponent(CommandGateway.class);
commandGateway.sendAndWait(createCourse);
commandGateway.sendAndWait(renameCourse);
commandGateway.sendAndWait(enrollStudent);
logger.info("Successfully executed sample commands");
} catch (Exception e) {
logger.log(Level.SEVERE, "Error while executing sample commands: " + e.getMessage(), e);
}
}
}
}
Updated the pom to include this
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
application.properties added with
spring.datasource.url=jdbc:h2:file:~/testdb
spring.datasource.username=sa
spring.jpa.hibernate.ddl-auto=update
spring.h2.console.enabled=true
Full stack trace below:
java.util.concurrent.CompletionException: java.lang.IllegalStateException: No value for key [HikariDataSource (HikariPool-1)] bound to thread
at java.base/java.util.concurrent.CompletableFuture.encodeRelay(CompletableFuture.java:368) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.uniComposeExceptionallyStage(CompletableFuture.java:1076) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.exceptionallyCompose(CompletableFuture.java:2411) ~[na:na]
at org.axonframework.messaging.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.lambda$safe$2(UnitOfWork.java:274) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at org.axonframework.messaging.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.lambda$runNextPhase$8(UnitOfWork.java:409) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1150) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:482) ~[na:na]
at org.axonframework.common.DirectExecutor.execute(DirectExecutor.java:54) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1184) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.thenComposeAsync(CompletableFuture.java:2352) ~[na:na]
at org.axonframework.messaging.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.lambda$runNextPhase$9(UnitOfWork.java:409) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[na:na]
at java.base/java.util.concurrent.ConcurrentLinkedQueue.forEachFrom(ConcurrentLinkedQueue.java:1037) ~[na:na]
at java.base/java.util.concurrent.ConcurrentLinkedQueue$CLQSpliterator.forEachRemaining(ConcurrentLinkedQueue.java:894) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
at java.base/java.util.stream.ReferencePipeline.reduce(ReferencePipeline.java:662) ~[na:na]
at org.axonframework.messaging.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.runNextPhase(UnitOfWork.java:411) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at org.axonframework.messaging.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.executeAllPhaseHandlers(UnitOfWork.java:359) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at org.axonframework.messaging.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.lambda$executeAllPhaseHandlers$5(UnitOfWork.java:362) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1150) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179) ~[na:na]
at org.axonframework.messaging.MessageStreamUtils$FirstResult.lambda$process$0(MessageStreamUtils.java:159) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at java.base/java.util.Optional.ifPresentOrElse(Optional.java:198) ~[na:na]
at org.axonframework.messaging.MessageStreamUtils$FirstResult.process(MessageStreamUtils.java:158) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at org.axonframework.messaging.EmptyMessageStream.onAvailable(EmptyMessageStream.java:63) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at org.axonframework.messaging.DelayedMessageStream.lambda$onAvailable$2(DelayedMessageStream.java:119) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510) ~[na:na]
at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179) ~[na:na]
at org.axonframework.messaging.MessageStreamUtils$Reducer.lambda$process$2(MessageStreamUtils.java:127) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at java.base/java.util.Optional.ifPresentOrElse(Optional.java:198) ~[na:na]
at org.axonframework.messaging.MessageStreamUtils$Reducer.process(MessageStreamUtils.java:126) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at io.axoniq.axonserver.connector.impl.AbstractBufferedStream.onCompleted(AbstractBufferedStream.java:95) ~[axonserver-connector-java-2025.2.0-EAP.jar:2025.2.0-EAP]
at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onClose(ClientCalls.java:479) ~[grpc-stub-1.69.0.jar:1.69.0]
at io.grpc.PartialForwardingClientCallListener.onClose(PartialForwardingClientCallListener.java:39) ~[grpc-api-1.69.0.jar:1.69.0]
at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:23) ~[grpc-api-1.69.0.jar:1.69.0]
at io.grpc.ForwardingClientCallListener$SimpleForwardingClientCallListener.onClose(ForwardingClientCallListener.java:40) ~[grpc-api-1.69.0.jar:1.69.0]
at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:564) ~[grpc-core-1.69.0.jar:1.69.0]
at io.grpc.internal.ClientCallImpl.access$100(ClientCallImpl.java:72) ~[grpc-core-1.69.0.jar:1.69.0]
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInternal(ClientCallImpl.java:729) ~[grpc-core-1.69.0.jar:1.69.0]
at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:710) ~[grpc-core-1.69.0.jar:1.69.0]
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) ~[grpc-core-1.69.0.jar:1.69.0]
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133) ~[grpc-core-1.69.0.jar:1.69.0]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Caused by: java.lang.IllegalStateException: No value for key [HikariDataSource (HikariPool-1)] bound to thread
at org.springframework.transaction.support.TransactionSynchronizationManager.unbindResource(TransactionSynchronizationManager.java:198) ~[spring-tx-6.2.11.jar:6.2.11]
at org.springframework.orm.jpa.JpaTransactionManager.doCleanupAfterCompletion(JpaTransactionManager.java:633) ~[spring-orm-6.2.11.jar:6.2.11]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.cleanupAfterCompletion(AbstractPlatformTransactionManager.java:1062) ~[spring-tx-6.2.11.jar:6.2.11]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:847) ~[spring-tx-6.2.11.jar:6.2.11]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:758) ~[spring-tx-6.2.11.jar:6.2.11]
at org.axonframework.extension.spring.messaging.unitofwork.SpringTransactionManager.commitTransaction(SpringTransactionManager.java:86) ~[axon-spring-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at org.axonframework.extension.spring.messaging.unitofwork.SpringTransactionManager$1.commit(SpringTransactionManager.java:69) ~[axon-spring-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at org.axonframework.messaging.unitofwork.TransactionalUnitOfWorkFactory.lambda$create$1(TransactionalUnitOfWorkFactory.java:88) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at org.axonframework.messaging.unitofwork.ProcessingLifecycle.lambda$runOn$0(ProcessingLifecycle.java:91) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
at org.axonframework.messaging.unitofwork.UnitOfWork$UnitOfWorkProcessingContext.lambda$safe$2(UnitOfWork.java:269) ~[axon-messaging-5.0.0-SNAPSHOT.jar:5.0.0-SNAPSHOT]
... 47 common frames omitted