-
Notifications
You must be signed in to change notification settings - Fork 3k
Change how JPAConfig cleans up its resources #45451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change how JPAConfig cleans up its resources #45451
Conversation
This comment has been minimized.
This comment has been minimized.
🎊 PR Preview fecf60a has been successfully built and deployed to https://quarkus-pr-main-45451-preview.surge.sh/version/main/guides/
|
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The approach looks good, though I have a few questions about the details...
// but that would force initialization of JPAConfig upon application shutdown, | ||
// which may cause cascading failures if the shutdown happened before JPAConfig was initialized. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So... what about this? :)
I.e. if something fails while starting datasources (invalid credentials, ...), will we now see Quarkus attempt to start JPA just to shut it down, with stacktraces being appended after the real problem (datasource credentials)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙈🙈🙈😃
I've tried running a test with an incorrect password and with/without these injection points. Both result in the same log:
2025-02-07 09:18:23,091 WARN [io.qua.run.log.LoggingSetupRecorder] (build-49) Log level TRACE for category 'io.quarkus.hibernate.orm.runtime' set below minimum logging level DEBUG, promoting it to DEBUG. Set the build time configuration property 'quarkus.log.category."io.quarkus.hibernate.orm.runtime".min-level' to 'TRACE' to avoid this warning
2025-02-07 09:18:24,129 DEBUG [io.qua.hib.orm.run.ser.FlatClassLoaderService] (main) HHH000194: Package not found or no package-info.java: io.quarkus.it.jpa.postgresql.defaultpu
2025-02-07 09:18:24,136 DEBUG [io.qua.hib.orm.run.ser.FlatClassLoaderService] (main) HHH000194: Package not found or no package-info.java: io.quarkus.it.jpa.postgresql.defaultpu
2025-02-07 09:18:24,138 DEBUG [io.qua.hib.orm.run.ser.FlatClassLoaderService] (main) HHH000194: Package not found or no package-info.java: io.quarkus.it.jpa.postgresql.defaultpu
2025-02-07 09:18:24,140 DEBUG [io.qua.hib.orm.run.ser.FlatClassLoaderService] (main) HHH000194: Package not found or no package-info.java: io.quarkus.it.jpa.postgresql.defaultpu
2025-02-07 09:18:24,142 DEBUG [io.qua.hib.orm.run.ser.FlatClassLoaderService] (main) HHH000194: Package not found or no package-info.java: io.quarkus.it.jpa.postgresql.defaultpu
2025-02-07 09:18:24,171 DEBUG [io.qua.hib.orm.run.ser.FlatClassLoaderService] (main) HHH000194: Package not found or no package-info.java: io.quarkus.it.jpa.postgresql.otherpu
2025-02-07 09:18:24,303 WARN [io.qua.run.log.LoggingSetupRecorder] (main) Log level TRACE for category 'io.quarkus.hibernate.orm.runtime' set below minimum logging level DEBUG, promoting it to DEBUG. Set the build time configuration property 'quarkus.log.category."io.quarkus.hibernate.orm.runtime".min-level' to 'TRACE' to avoid this warning
2025-02-07 09:18:24,307 DEBUG [io.qua.hib.orm.run.FastBootHibernatePersistenceProvider] (JPA Startup Thread: other) Located 2 persistence units; checking each
2025-02-07 09:18:24,307 DEBUG [io.qua.hib.orm.run.FastBootHibernatePersistenceProvider] (JPA Startup Thread: <default>) Located 2 persistence units; checking each
2025-02-07 09:18:24,307 DEBUG [io.qua.hib.orm.run.FastBootHibernatePersistenceProvider] (JPA Startup Thread: other) Checking persistence-unit [name=<default>, explicit-provider=null] against incoming persistence unit name [other]
2025-02-07 09:18:24,307 DEBUG [io.qua.hib.orm.run.FastBootHibernatePersistenceProvider] (JPA Startup Thread: <default>) Checking persistence-unit [name=<default>, explicit-provider=null] against incoming persistence unit name [<default>]
2025-02-07 09:18:24,307 DEBUG [io.qua.hib.orm.run.FastBootHibernatePersistenceProvider] (JPA Startup Thread: other) Excluding from consideration '<default>' due to name mismatch
2025-02-07 09:18:24,307 DEBUG [io.qua.hib.orm.run.FastBootHibernatePersistenceProvider] (JPA Startup Thread: other) Checking persistence-unit [name=other, explicit-provider=null] against incoming persistence unit name [other]
2025-02-07 09:18:24,307 DEBUG [io.qua.hib.orm.run.FastBootHibernatePersistenceProvider] (JPA Startup Thread: <default>) No PersistenceProvider explicitly requested, assuming Hibernate
2025-02-07 09:18:24,307 DEBUG [io.qua.hib.orm.run.FastBootHibernatePersistenceProvider] (JPA Startup Thread: other) No PersistenceProvider explicitly requested, assuming Hibernate
2025-02-07 09:18:24,409 WARN [io.agr.pool] (agroal-11) Datasource '<default>': FATAL: password authentication failed for user "hibernate_orm_test"
2025-02-07 09:18:24,409 WARN [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: other) SQL Error: 0, SQLState: 28P01
2025-02-07 09:18:24,409 ERROR [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: other) FATAL: password authentication failed for user "hibernate_orm_test"
2025-02-07 09:18:24,410 WARN [org.hib.eng.jdb.env.int.JdbcEnvironmentInitiator] (JPA Startup Thread: other) HHH000342: Could not obtain connection to query metadata: org.hibernate.exception.GenericJDBCException: unable to obtain isolated JDBC connection [FATAL: password authentication failed for user "hibernate_orm_test"] [n/a]
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:63)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:108)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:94)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.doTheWork(JtaIsolationDelegate.java:206)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.lambda$delegateWork$3(JtaIsolationDelegate.java:91)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.doInSuspendedTransaction(JtaIsolationDelegate.java:125)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.delegateWork(JtaIsolationDelegate.java:88)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentUsingJdbcMetadata(JdbcEnvironmentInitiator.java:320)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:129)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:81)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:130)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:238)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:215)
at org.hibernate.service.ServiceRegistry.requireService(ServiceRegistry.java:68)
at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:52)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:136)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:247)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:215)
at org.hibernate.service.ServiceRegistry.requireService(ServiceRegistry.java:68)
at org.hibernate.boot.internal.SessionFactoryOptionsBuilder.<init>(SessionFactoryOptionsBuilder.java:290)
at io.quarkus.hibernate.orm.runtime.recording.PrevalidatedQuarkusMetadata.buildSessionFactoryOptionsBuilder(PrevalidatedQuarkusMetadata.java:72)
at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.build(FastBootEntityManagerFactoryBuilder.java:84)
at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.createEntityManagerFactory(FastBootHibernatePersistenceProvider.java:72)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:80)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at io.quarkus.hibernate.orm.runtime.JPAConfig$LazyPersistenceUnit.get(JPAConfig.java:160)
at io.quarkus.hibernate.orm.runtime.JPAConfig$1.run(JPAConfig.java:61)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: org.postgresql.util.PSQLException: FATAL: password authentication failed for user "hibernate_orm_test"
at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:704)
at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:213)
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:268)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:54)
at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:273)
at org.postgresql.Driver.makeConnection(Driver.java:446)
at org.postgresql.Driver.connect(Driver.java:298)
at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:225)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:580)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:561)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:75)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
... 1 more
2025-02-07 09:18:24,415 WARN [io.agr.pool] (agroal-11) Datasource '<default>': FATAL: password authentication failed for user "hibernate_orm_test"
2025-02-07 09:18:24,415 WARN [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: <default>) SQL Error: 0, SQLState: 28P01
2025-02-07 09:18:24,416 ERROR [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: <default>) FATAL: password authentication failed for user "hibernate_orm_test"
2025-02-07 09:18:24,416 WARN [org.hib.eng.jdb.env.int.JdbcEnvironmentInitiator] (JPA Startup Thread: <default>) HHH000342: Could not obtain connection to query metadata: org.hibernate.exception.GenericJDBCException: unable to obtain isolated JDBC connection [FATAL: password authentication failed for user "hibernate_orm_test"] [n/a]
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:63)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:108)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:94)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.doTheWork(JtaIsolationDelegate.java:206)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.lambda$delegateWork$3(JtaIsolationDelegate.java:91)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.doInSuspendedTransaction(JtaIsolationDelegate.java:125)
at org.hibernate.resource.transaction.backend.jta.internal.JtaIsolationDelegate.delegateWork(JtaIsolationDelegate.java:88)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.getJdbcEnvironmentUsingJdbcMetadata(JdbcEnvironmentInitiator.java:320)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:129)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:81)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:130)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:263)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:238)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:215)
at org.hibernate.service.ServiceRegistry.requireService(ServiceRegistry.java:68)
at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:52)
at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:136)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:247)
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:215)
at org.hibernate.service.ServiceRegistry.requireService(ServiceRegistry.java:68)
at org.hibernate.boot.internal.SessionFactoryOptionsBuilder.<init>(SessionFactoryOptionsBuilder.java:290)
at io.quarkus.hibernate.orm.runtime.recording.PrevalidatedQuarkusMetadata.buildSessionFactoryOptionsBuilder(PrevalidatedQuarkusMetadata.java:72)
at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.build(FastBootEntityManagerFactoryBuilder.java:84)
at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.createEntityManagerFactory(FastBootHibernatePersistenceProvider.java:72)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:80)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at io.quarkus.hibernate.orm.runtime.JPAConfig$LazyPersistenceUnit.get(JPAConfig.java:160)
at io.quarkus.hibernate.orm.runtime.JPAConfig$1.run(JPAConfig.java:61)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: org.postgresql.util.PSQLException: FATAL: password authentication failed for user "hibernate_orm_test"
at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:704)
at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:213)
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:268)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:54)
at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:273)
at org.postgresql.Driver.makeConnection(Driver.java:446)
at org.postgresql.Driver.connect(Driver.java:298)
at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:225)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:580)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:561)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:75)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
... 1 more
2025-02-07 09:18:24,636 WARN [io.agr.pool] (agroal-11) Datasource '<default>': FATAL: password authentication failed for user "hibernate_orm_test"
2025-02-07 09:18:24,636 WARN [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: other) SQL Error: 0, SQLState: 28P01
2025-02-07 09:18:24,636 ERROR [org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread: other) FATAL: password authentication failed for user "hibernate_orm_test"
java.lang.RuntimeException: java.lang.RuntimeException: Failed to start quarkus
at io.quarkus.test.junit.QuarkusTestExtension.throwBootFailureException(QuarkusTestExtension.java:611)
at io.quarkus.test.junit.QuarkusTestExtension.interceptTestClassConstructor(QuarkusTestExtension.java:695)
at java.base/java.util.Optional.orElseGet(Optional.java:364)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: java.lang.RuntimeException: Failed to start quarkus
at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
at io.quarkus.runtime.Application.start(Application.java:101)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at io.quarkus.runner.bootstrap.StartupActionImpl.run(StartupActionImpl.java:305)
at io.quarkus.test.junit.QuarkusTestExtension.doJavaStart(QuarkusTestExtension.java:224)
at io.quarkus.test.junit.QuarkusTestExtension.ensureStarted(QuarkusTestExtension.java:578)
at io.quarkus.test.junit.QuarkusTestExtension.beforeAll(QuarkusTestExtension.java:628)
... 1 more
Caused by: jakarta.persistence.PersistenceException: [PersistenceUnit: other] Unable to build Hibernate SessionFactory
at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.persistenceException(FastBootEntityManagerFactoryBuilder.java:129)
at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.build(FastBootEntityManagerFactoryBuilder.java:89)
at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.createEntityManagerFactory(FastBootHibernatePersistenceProvider.java:72)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:80)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at io.quarkus.hibernate.orm.runtime.JPAConfig$LazyPersistenceUnit.get(JPAConfig.java:160)
at io.quarkus.hibernate.orm.runtime.JPAConfig$1.run(JPAConfig.java:61)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: org.hibernate.exception.GenericJDBCException: Unable to open JDBC Connection for DDL execution [FATAL: password authentication failed for user "hibernate_orm_test"] [n/a]
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:63)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:108)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:94)
at org.hibernate.resource.transaction.backend.jta.internal.DdlTransactionIsolatorJtaImpl.getIsolatedConnection(DdlTransactionIsolatorJtaImpl.java:77)
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.getIsolatedConnection(GenerationTargetToDatabase.java:60)
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.jdbcStatement(GenerationTargetToDatabase.java:112)
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:79)
at org.hibernate.tool.schema.internal.Helper.applySqlString(Helper.java:233)
at org.hibernate.tool.schema.internal.SchemaDropperImpl.dropFromMetadata(SchemaDropperImpl.java:213)
at org.hibernate.tool.schema.internal.SchemaDropperImpl.performDrop(SchemaDropperImpl.java:186)
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:156)
at org.hibernate.tool.schema.internal.SchemaDropperImpl.doDrop(SchemaDropperImpl.java:116)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.performDatabaseAction(SchemaManagementToolCoordinator.java:238)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.lambda$process$5(SchemaManagementToolCoordinator.java:144)
at java.base/java.util.HashMap.forEach(HashMap.java:1421)
at org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.process(SchemaManagementToolCoordinator.java:141)
at io.quarkus.hibernate.orm.runtime.observers.SessionFactoryObserverForSchemaExport.sessionFactoryCreated(SessionFactoryObserverForSchemaExport.java:21)
at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:35)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:324)
at io.quarkus.hibernate.orm.runtime.boot.FastBootEntityManagerFactoryBuilder.build(FastBootEntityManagerFactoryBuilder.java:87)
... 6 more
Caused by: org.postgresql.util.PSQLException: FATAL: password authentication failed for user "hibernate_orm_test"
at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:704)
at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:213)
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:268)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:54)
at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:273)
at org.postgresql.Driver.makeConnection(Driver.java:446)
at org.postgresql.Driver.connect(Driver.java:298)
at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:225)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:580)
at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:561)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at --- Async.Stack.Trace --- (captured by IntelliJ IDEA debugger)
at java.base/java.util.concurrent.FutureTask.<init>(FutureTask.java:132)
at io.agroal.pool.util.PriorityScheduledExecutor.executeNow(PriorityScheduledExecutor.java:51)
at io.agroal.pool.ConnectionPool.handlerFromSharedCache(ConnectionPool.java:329)
at io.agroal.pool.ConnectionPool.getConnection(ConnectionPool.java:288)
at io.agroal.pool.DataSource.getConnection(DataSource.java:86)
at io.quarkus.hibernate.orm.runtime.customized.QuarkusConnectionProvider.getConnection(QuarkusConnectionProvider.java:23)
at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:467)
at org.hibernate.resource.transaction.backend.jta.internal.DdlTransactionIsolatorJtaImpl.getIsolatedConnection(DdlTransactionIsolatorJtaImpl.java:74)
... 22 more
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, but then I was wrong about credentials, since it obviously didn't make the datasource startup fail.
Maybe a JDBc URL with an invalid syntax?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, I've tried a bad URL (some random text), using postgres url with oracle driver (Driver does not support the provided URL
), no DB running -- same results as above 😕
if I try to use some random string for db-kind
, things fail at build time without getting to the Hibernate ORM stuff:
java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[error]: Build step io.quarkus.agroal.deployment.AgroalProcessor#build threw an exception: io.quarkus.runtime.configuration.ConfigurationException: Unable to find a JDBC driver corresponding to the database kind 'oracleaa' for the default datasource (available: 'oracle','postgresql'). Check if it's a typo, otherwise provide a suitable JDBC driver extension, define the driver manually, or disable the JDBC datasource by adding 'quarkus.datasource.jdbc=false' to your configuration if you don't need it.
at io.quarkus.agroal.deployment.AgroalProcessor.resolveDriver(AgroalProcessor.java:358)
at io.quarkus.agroal.deployment.AgroalProcessor.getAggregatedConfigBuildItems(AgroalProcessor.java:332)
at io.quarkus.agroal.deployment.AgroalProcessor.build(AgroalProcessor.java:103)
at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)
at io.quarkus.builder.BuildContext.run(BuildContext.java:255)
at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2675)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2654)
at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1627)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1594)
at java.base/java.lang.Thread.run(Thread.java:840)
at org.jboss.threads.JBossThread.run(JBossThread.java:499)
at io.quarkus.test.junit.QuarkusTestExtension.throwBootFailureException(QuarkusTestExtension.java:611)
at io.quarkus.test.junit.QuarkusTestExtension.interceptTestClassConstructor(QuarkusTestExtension.java:706)
at java.base/java.util.Optional.orElseGet(Optional.java:364)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[error]: Build step io.quarkus.agroal.deployment.AgroalProcessor#build threw an exception: io.quarkus.runtime.configuration.ConfigurationException: Unable to find a JDBC driver corresponding to the database kind 'oracleaa' for the default datasource (available: 'oracle','postgresql'). Check if it's a typo, otherwise provide a suitable JDBC driver extension, define the driver manually, or disable the JDBC datasource by adding 'quarkus.datasource.jdbc=false' to your configuration if you don't need it.
at io.quarkus.agroal.deployment.AgroalProcessor.resolveDriver(AgroalProcessor.java:358)
at io.quarkus.agroal.deployment.AgroalProcessor.getAggregatedConfigBuildItems(AgroalProcessor.java:332)
at io.quarkus.agroal.deployment.AgroalProcessor.build(AgroalProcessor.java:103)
at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)
at io.quarkus.builder.BuildContext.run(BuildContext.java:255)
at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2675)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2654)
at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1627)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1594)
at java.base/java.lang.Thread.run(Thread.java:840)
at org.jboss.threads.JBossThread.run(JBossThread.java:499)
at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:354)
at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:271)
at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:61)
at io.quarkus.test.junit.QuarkusTestExtension.doJavaStart(QuarkusTestExtension.java:195)
at io.quarkus.test.junit.QuarkusTestExtension.ensureStarted(QuarkusTestExtension.java:578)
at io.quarkus.test.junit.QuarkusTestExtension.beforeAll(QuarkusTestExtension.java:628)
... 1 more
Caused by: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[error]: Build step io.quarkus.agroal.deployment.AgroalProcessor#build threw an exception: io.quarkus.runtime.configuration.ConfigurationException: Unable to find a JDBC driver corresponding to the database kind 'oracleaa' for the default datasource (available: 'oracle','postgresql'). Check if it's a typo, otherwise provide a suitable JDBC driver extension, define the driver manually, or disable the JDBC datasource by adding 'quarkus.datasource.jdbc=false' to your configuration if you don't need it.
at io.quarkus.agroal.deployment.AgroalProcessor.resolveDriver(AgroalProcessor.java:358)
at io.quarkus.agroal.deployment.AgroalProcessor.getAggregatedConfigBuildItems(AgroalProcessor.java:332)
at io.quarkus.agroal.deployment.AgroalProcessor.build(AgroalProcessor.java:103)
at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)
at io.quarkus.builder.BuildContext.run(BuildContext.java:255)
at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2675)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2654)
at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1627)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1594)
at java.base/java.lang.Thread.run(Thread.java:840)
at org.jboss.threads.JBossThread.run(JBossThread.java:499)
at io.quarkus.builder.Execution.run(Execution.java:122)
at io.quarkus.builder.BuildExecutionBuilder.execute(BuildExecutionBuilder.java:78)
at io.quarkus.deployment.QuarkusAugmentor.run(QuarkusAugmentor.java:161)
at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:350)
... 6 more
Caused by: io.quarkus.runtime.configuration.ConfigurationException: Unable to find a JDBC driver corresponding to the database kind 'oracleaa' for the default datasource (available: 'oracle','postgresql'). Check if it's a typo, otherwise provide a suitable JDBC driver extension, define the driver manually, or disable the JDBC datasource by adding 'quarkus.datasource.jdbc=false' to your configuration if you don't need it.
at io.quarkus.agroal.deployment.AgroalProcessor.resolveDriver(AgroalProcessor.java:358)
at io.quarkus.agroal.deployment.AgroalProcessor.getAggregatedConfigBuildItems(AgroalProcessor.java:332)
at io.quarkus.agroal.deployment.AgroalProcessor.build(AgroalProcessor.java:103)
at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)
at io.quarkus.builder.BuildContext.run(BuildContext.java:255)
at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2675)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2654)
at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1627)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1594)
at java.base/java.lang.Thread.run(Thread.java:840)
at org.jboss.threads.JBossThread.run(JBossThread.java:499)
I just thought about it... wouldn't the work you've done for active/inactive datasources let the app run till it reaches a point it wants to use a datasource and only then fail (which, in my test, is ORM attempts to get db metadata)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, I've tried a bad URL (some random text), using postgres url with oracle driver (Driver does not support the provided URL), no DB running -- same results as above 😕
if I try to use some random string for db-kind, things fail at build time without getting to the Hibernate ORM stuff:
Looks like URLs are resolved on first use. Bummer. We'd need something that triggers a failure on runtime init, but when Agroal starts (presumably before Hibernate ORM).
Maybe setting the pool's min size above the max size, something like that?
I just thought about it... wouldn't the work you've done for active/inactive datasources let the app run till it reaches a point it wants to use a datasource and only then fail (which, in my test, is ORM attempts to get db metadata)?
No, my work would only disable the datasource if the JDBC url is not set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe setting the pool's min size above the max size, something like that?
mm, AgroalConnectionPoolConfigurationSupplier
has validation that can throw exceptions. The validation happens when the datasource is created (DataSources#createDataSource()
), which in this case is when ORM wants to create a PU, leading to:
java.lang.RuntimeException: java.lang.RuntimeException: Failed to start quarkus
at io.quarkus.test.junit.QuarkusTestExtension.throwBootFailureException(QuarkusTestExtension.java:611)
at io.quarkus.test.junit.QuarkusTestExtension.interceptTestClassConstructor(QuarkusTestExtension.java:706)
at java.base/java.util.Optional.orElseGet(Optional.java:364)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: java.lang.RuntimeException: Failed to start quarkus
at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
at io.quarkus.runtime.Application.start(Application.java:101)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at io.quarkus.runner.bootstrap.StartupActionImpl.run(StartupActionImpl.java:305)
at io.quarkus.test.junit.QuarkusTestExtension.doJavaStart(QuarkusTestExtension.java:224)
at io.quarkus.test.junit.QuarkusTestExtension.ensureStarted(QuarkusTestExtension.java:578)
at io.quarkus.test.junit.QuarkusTestExtension.beforeAll(QuarkusTestExtension.java:628)
... 1 more
Caused by: io.quarkus.runtime.configuration.ConfigurationException: Unable to find datasource '<default>' for persistence unit 'other': Error creating synthetic bean [sqqLi56D50iCdXmOjyjPSAxbLu0]: java.lang.IllegalArgumentException: Invalid min size: greater than max size
at io.quarkus.hibernate.orm.runtime.PersistenceUnitUtil.unableToFindDataSource(PersistenceUnitUtil.java:115)
at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.injectDataSource(FastBootHibernatePersistenceProvider.java:392)
at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.buildRuntimeSettings(FastBootHibernatePersistenceProvider.java:209)
at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.getEntityManagerFactoryBuilderOrNull(FastBootHibernatePersistenceProvider.java:180)
at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.createEntityManagerFactory(FastBootHibernatePersistenceProvider.java:66)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:80)
at jakarta.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at io.quarkus.hibernate.orm.runtime.JPAConfig$LazyPersistenceUnit.get(JPAConfig.java:160)
at io.quarkus.hibernate.orm.runtime.JPAConfig$1.run(JPAConfig.java:61)
at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: jakarta.enterprise.inject.CreationException: Error creating synthetic bean [sqqLi56D50iCdXmOjyjPSAxbLu0]: java.lang.IllegalArgumentException: Invalid min size: greater than max size
at io.agroal.api.AgroalDataSource_sqqLi56D50iCdXmOjyjPSAxbLu0_Synthetic_Bean.doCreate(Unknown Source)
at io.agroal.api.AgroalDataSource_sqqLi56D50iCdXmOjyjPSAxbLu0_Synthetic_Bean.create(Unknown Source)
at io.agroal.api.AgroalDataSource_sqqLi56D50iCdXmOjyjPSAxbLu0_Synthetic_Bean.create(Unknown Source)
at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:119)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:38)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:35)
at io.quarkus.arc.generator.Default_jakarta_enterprise_context_ApplicationScoped_ContextInstances.c11(Unknown Source)
at io.quarkus.arc.generator.Default_jakarta_enterprise_context_ApplicationScoped_ContextInstances.computeIfAbsent(Unknown Source)
at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:35)
at io.quarkus.arc.impl.ClientProxies.getApplicationScopedDelegate(ClientProxies.java:23)
at io.agroal.api.AgroalDataSource_sqqLi56D50iCdXmOjyjPSAxbLu0_Synthetic_ClientProxy.arc$delegate(Unknown Source)
at io.agroal.api.AgroalDataSource_sqqLi56D50iCdXmOjyjPSAxbLu0_Synthetic_ClientProxy.arc_contextualInstance(Unknown Source)
at io.quarkus.arc.ClientProxy.unwrap(ClientProxy.java:52)
at io.quarkus.hibernate.orm.runtime.FastBootHibernatePersistenceProvider.injectDataSource(FastBootHibernatePersistenceProvider.java:390)
... 8 more
Caused by: java.lang.IllegalArgumentException: Invalid min size: greater than max size
at io.agroal.api.configuration.supplier.AgroalConnectionPoolConfigurationSupplier.validate(AgroalConnectionPoolConfigurationSupplier.java:317)
at io.agroal.api.configuration.supplier.AgroalConnectionPoolConfigurationSupplier.get(AgroalConnectionPoolConfigurationSupplier.java:349)
at io.agroal.api.configuration.supplier.AgroalDataSourceConfigurationSupplier.validate(AgroalDataSourceConfigurationSupplier.java:108)
at io.agroal.api.configuration.supplier.AgroalDataSourceConfigurationSupplier.get(AgroalDataSourceConfigurationSupplier.java:114)
at io.quarkus.agroal.runtime.DataSources.createDataSource(DataSources.java:208)
at io.quarkus.agroal.runtime.AgroalRecorder$3.apply(AgroalRecorder.java:65)
at io.quarkus.agroal.runtime.AgroalRecorder$3.apply(AgroalRecorder.java:60)
at io.agroal.api.AgroalDataSource_sqqLi56D50iCdXmOjyjPSAxbLu0_Synthetic_Bean.createSynthetic(Unknown Source)
... 22 more
I tried to look a bit more into this, and AFAIU, if the app fails at startup we never reach this part:
Lines 27 to 29 in 046dc99
recorder.handleLifecycleEvents(shutdown, launchMode.getLaunchMode(), | |
config.test().disableApplicationLifecycleObservers()); | |
return new ApplicationStartBuildItem(); |
which means we don't fire the startup event and do not register the shutdown task to fire shutdown events ...
quarkus/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ArcRecorder.java
Lines 114 to 121 in 046dc99
fireLifecycleEvent(container, new StartupEvent(), mockBeanClasses); | |
context.addShutdownTask(new Runnable() { | |
@Override | |
public void run() { | |
fireLifecycleEvent(container, new ShutdownEvent(ApplicationLifecycleManager.shutdownReason), mockBeanClasses); | |
} | |
}); |
if that's so then I guess we should probably keep the destroyer for the JPAConfig
as well as the observer. Observer will close things nicely if all goes well, and if we end up stopping the app before it could even start then the destroyer will make an attempt to close those PUs, just in case the app failed after we've started the PUs but before the shutdown task was added...
Another thought occurred to me... could we just register a shutdown task for ORM and not deal with destroyers and observers 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mm, AgroalConnectionPoolConfigurationSupplier has validation that can throw exceptions. The validation happens when the datasource is created (DataSources#createDataSource()), which in this case is when ORM wants to create a PU
This hints at another ordering problem during creation, because the intent is to have datasources created on startup:
quarkus/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalProcessor.java
Lines 267 to 276 in a978058
SyntheticBeanBuildItem.ExtendedBeanConfigurator configurator = SyntheticBeanBuildItem | |
.configure(AgroalDataSource.class) | |
.addType(DATA_SOURCE) | |
.addType(AGROAL_DATA_SOURCE) | |
.scope(ApplicationScoped.class) | |
.qualifiers(qualifiers(dataSourceName)) | |
.setRuntimeInit() | |
.unremovable() | |
.addInjectionPoint(ClassType.create(DotName.createSimple(DataSources.class))) | |
.startup() |
If datasources are created when Hibernate ORM first retrieves them, it means Hibernate ORM gets initialized before Agroal, and the only reason it works is that Arc is nice enough to trigger initialization immediately if it didn't happen yet.
It feels like we could improve this as well... making sure Agroal gets initialized before Hibernate ORM?
Another thought occurred to me... could we just register a shutdown task for ORM and not deal with destroyers and observers 😄
Okay, but then we must be sure that shutdown task gets executed before Agroal gets shut down.
We're getting out of scope, though...
Eventually, what we need is a mechanism that:
- Initializes things in this order: Agroal => Hibernate ORM => Application
- Cleans up things in this order: Application => Hibernate ORM => Agroal
- Does not initialize Agroal/Hibernate ORM when cleaning them up -- e.g. if Agroal initialization fails, we don't want Hibernate ORM cleanup to trigger initialization of Hibernate ORM.
AFAICS, on main
, we only comply with rule 3. Rule 1 is sort of irrelevant due to "lazy initialization" of Agroal -- it does lead to annoying stack traces like the one you witnessed, but that's really another issue.
To fix #34547 , we'd need to comply with rule 2.
If your PR makes sure we now comply with rule 2, and still comply with rule 3, let's merge and file a separate issue to tackle rule 1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the status of this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say it needs a bit more time... i.e I'm sure (2) works fine as long as the app startup does not fail, I'm not so sure it works that way if there's a failure during the startup. But I haven't come up with a test to check it yet 😕
...m/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmCdiProcessor.java
Show resolved
Hide resolved
integration-tests/hibernate-search-orm-elasticsearch-outbox-polling/pom.xml
Show resolved
Hide resolved
...m/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/HibernateOrmCdiProcessor.java
Show resolved
Hide resolved
instead of relaying on a Destroyer. This way other components e.g. datasource should still be available.
620beda
to
73b6945
Compare
Status for workflow
|
Status for workflow
|
Superseded by #46357, closing. |
fixes #34547
As we discussed in the linked issue, the order in which beans are destroyed is not guaranteed. With this patch, JPAConfig will observe the shutdown event and clean up the resources then.
Since persistent units are now going to be closed prior to datasource being destroyed this should allow Hibernate Search to stop things cleanly.
For the observer priority I've initially used the
ObserverMethod.DEFAULT_PRIORITY
as the base value but then noticed that it uses the one from thejakarta.interceptor.Interceptor.Priority
and thought that:might be the one applicable here 😃