Skip to content
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

Exception on application shutdown with quarkus-hibernate-search-orm-coordination-outbox-polling #34547

Open
yrodiere opened this issue Jul 5, 2023 · 8 comments
Labels
area/hibernate-search Hibernate Search kind/bug Something isn't working

Comments

@yrodiere
Copy link
Member

yrodiere commented Jul 5, 2023

Describe the bug

When using the extension quarkus-hibernate-search-orm-coordination-outbox-polling and stopping the application in dev mode, exception gets thrown, caused by Hibernate Search not being able to create a connection to the database (it needs to in order to re-register agents).

Expected behavior

No exception.

Actual behavior

2023-07-05 13:57:12,576 ERROR [org.hib.sea.eng.rep.spi.RootFailureCollector] (Shutdown thread) HSEARCH000521: Hibernate Search encountered a failure during %1$s; continuing for now to list all problems, but the process will ultimately be aborted.
Context: %2$s
Failure: [Error Occurred After Shutdown]: org.hibernate.exception.GenericJDBCException: Unable to acquire JDBC Connection [This pool is closed and does not handle any more connections!] [n/a]
        at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:61)
        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.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:116)
        at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:143)
        at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.connection(StatementPreparerImpl.java:51)
        at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$1.doPrepare(StatementPreparerImpl.java:91)
        at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:177)
        at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareStatement(StatementPreparerImpl.java:76)
        at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.lambda$list$0(JdbcSelectExecutorStandardImpl.java:102)
        at org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess.executeQuery(DeferredResultSetAccess.java:226)
        at org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess.getResultSet(DeferredResultSetAccess.java:163)
        at org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.advanceNext(JdbcValuesResultSetImpl.java:254)
        at org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl.processNext(JdbcValuesResultSetImpl.java:134)
        at org.hibernate.sql.results.jdbc.internal.AbstractJdbcValues.next(AbstractJdbcValues.java:19)
        at org.hibernate.sql.results.internal.RowProcessingStateStandardImpl.next(RowProcessingStateStandardImpl.java:66)
        at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:178)
        at org.hibernate.sql.results.spi.ListResultsConsumer.consume(ListResultsConsumer.java:33)
        at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.doExecuteQuery(JdbcSelectExecutorStandardImpl.java:361)
        at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.executeQuery(JdbcSelectExecutorStandardImpl.java:168)
        at org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl.list(JdbcSelectExecutorStandardImpl.java:93)
        at org.hibernate.sql.exec.spi.JdbcSelectExecutor.list(JdbcSelectExecutor.java:31)
        at org.hibernate.loader.ast.internal.LoaderHelper.loadByArrayParameter(LoaderHelper.java:215)
        at org.hibernate.loader.ast.internal.EntityBatchLoaderArrayParam.initializeEntities(EntityBatchLoaderArrayParam.java:141)
        at org.hibernate.loader.ast.internal.EntityBatchLoaderArrayParam.load(EntityBatchLoaderArrayParam.java:98)
        at org.hibernate.loader.ast.internal.EntityBatchLoaderArrayParam.load(EntityBatchLoaderArrayParam.java:170)
        at org.hibernate.persister.entity.AbstractEntityPersister.doLoad(AbstractEntityPersister.java:3481)
        at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:3471)
        at org.hibernate.event.internal.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:581)
        at org.hibernate.event.internal.DefaultLoadEventListener.loadFromCacheOrDatasource(DefaultLoadEventListener.java:567)
        at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:536)
        at org.hibernate.event.internal.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:529)
        at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:202)
        at org.hibernate.event.internal.DefaultLoadEventListener.loadWithRegularProxy(DefaultLoadEventListener.java:282)
        at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:237)
        at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:106)
        at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:78)
        at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:138)
        at org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1231)
        at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1219)
        at org.hibernate.loader.internal.IdentifierLoadAccessImpl.doLoad(IdentifierLoadAccessImpl.java:194)
        at org.hibernate.loader.internal.IdentifierLoadAccessImpl.lambda$load$1(IdentifierLoadAccessImpl.java:160)
        at org.hibernate.loader.internal.IdentifierLoadAccessImpl.perform(IdentifierLoadAccessImpl.java:107)
        at org.hibernate.loader.internal.IdentifierLoadAccessImpl.load(IdentifierLoadAccessImpl.java:160)
        at org.hibernate.internal.SessionImpl.find(SessionImpl.java:2406)
        at org.hibernate.internal.SessionImpl.find(SessionImpl.java:2372)
        at org.hibernate.search.mapper.orm.coordination.outboxpolling.cluster.impl.DefaultAgentRepository.find(DefaultAgentRepository.java:31)
        at org.hibernate.search.mapper.orm.coordination.outboxpolling.cluster.impl.AgentPersister.leaveCluster(AgentPersister.java:61)
        at org.hibernate.search.mapper.orm.coordination.outboxpolling.event.impl.AbstractAgentClusterLink.leaveCluster(AbstractAgentClusterLink.java:138)
        at org.hibernate.search.mapper.orm.coordination.outboxpolling.event.impl.AgentClusterLinkContextProvider.lambda$inTransaction$0(AgentClusterLinkContextProvider.java:31)
        at org.hibernate.search.mapper.orm.coordination.outboxpolling.event.impl.AgentClusterLinkContextProvider.inTransaction(AgentClusterLinkContextProvider.java:42)
        at org.hibernate.search.mapper.orm.coordination.outboxpolling.event.impl.AgentClusterLinkContextProvider.inTransaction(AgentClusterLinkContextProvider.java:30)
        at org.hibernate.search.mapper.orm.coordination.outboxpolling.event.impl.OutboxPollingEventProcessor.leaveCluster(OutboxPollingEventProcessor.java:216)
        at org.hibernate.search.util.common.impl.AbstractCloser.push(AbstractCloser.java:53)
        at org.hibernate.search.util.common.impl.AbstractCloser.push(AbstractCloser.java:33)
        at org.hibernate.search.mapper.orm.coordination.outboxpolling.event.impl.OutboxPollingEventProcessor.stop(OutboxPollingEventProcessor.java:211)
        at org.hibernate.search.util.common.impl.AbstractCloser.push(AbstractCloser.java:53)
        at org.hibernate.search.util.common.impl.AbstractCloser.pushAll(AbstractCloser.java:92)
        at org.hibernate.search.util.common.impl.AbstractCloser.pushAll(AbstractCloser.java:73)
        at org.hibernate.search.mapper.orm.coordination.outboxpolling.impl.OutboxPollingCoordinationStrategy.stop(OutboxPollingCoordinationStrategy.java:197)
        at org.hibernate.search.util.common.impl.AbstractCloser.push(AbstractCloser.java:53)
        at org.hibernate.search.mapper.orm.mapping.impl.HibernateOrmMapping.doStop(HibernateOrmMapping.java:196)
        at org.hibernate.search.util.common.impl.AbstractCloser.push(AbstractCloser.java:53)
        at org.hibernate.search.util.common.impl.AbstractCloser.push(AbstractCloser.java:33)
        at org.hibernate.search.mapper.pojo.mapping.spi.AbstractPojoMappingImplementor.stop(AbstractPojoMappingImplementor.java:68)
        at org.hibernate.search.engine.common.impl.SearchIntegrationImpl.lambda$close$2(SearchIntegrationImpl.java:132)
        at org.hibernate.search.engine.common.impl.SearchIntegrationImpl.stopAllSafely(SearchIntegrationImpl.java:178)
        at org.hibernate.search.engine.common.impl.SearchIntegrationImpl.close(SearchIntegrationImpl.java:131)
        at org.hibernate.search.mapper.orm.mapping.impl.HibernateSearchContextProviderService.close(HibernateSearchContextProviderService.java:36)
        at org.hibernate.search.mapper.orm.bootstrap.impl.HibernateOrmIntegrationBooterImpl.lambda$orchestrateBootAndShutdown$5(HibernateOrmIntegrationBooterImpl.java:156)
        at java.base/java.util.concurrent.CompletableFuture.biAccept(CompletableFuture.java:1386)
        at java.base/java.util.concurrent.CompletableFuture$BiAccept.tryFire(CompletableFuture.java:1355)
        at java.base/java.util.concurrent.CompletableFuture$CoCompletion.tryFire(CompletableFuture.java:1219)
        at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
        at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147)
        at org.hibernate.search.mapper.orm.bootstrap.impl.HibernateSearchSessionFactoryObserver.sessionFactoryClosing(HibernateSearchSessionFactoryObserver.java:50)
        at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryClosing(SessionFactoryObserverChain.java:48)
        at org.hibernate.internal.SessionFactoryImpl.close(SessionFactoryImpl.java:869)
        at io.quarkus.hibernate.orm.runtime.JPAConfig$LazyPersistenceUnit.close(JPAConfig.java:168)
        at io.quarkus.hibernate.orm.runtime.JPAConfig$Destroyer.destroy(JPAConfig.java:130)
        at io.quarkus.hibernate.orm.runtime.JPAConfig$Destroyer.destroy(JPAConfig.java:125)
        at io.quarkus.hibernate.orm.runtime.JPAConfig_b44400079827d7cae558c390d8d94cadbd711498_Synthetic_Bean.doDestroy(Unknown Source)
        at io.quarkus.hibernate.orm.runtime.JPAConfig_b44400079827d7cae558c390d8d94cadbd711498_Synthetic_Bean.destroy(Unknown Source)
        at io.quarkus.hibernate.orm.runtime.JPAConfig_b44400079827d7cae558c390d8d94cadbd711498_Synthetic_Bean.destroy(Unknown Source)
        at io.quarkus.arc.impl.AbstractInstanceHandle.destroyInternal(AbstractInstanceHandle.java:82)
        at io.quarkus.arc.impl.ContextInstanceHandleImpl.destroy(ContextInstanceHandleImpl.java:21)
        at io.quarkus.arc.impl.AbstractSharedContext.destroy(AbstractSharedContext.java:96)
        at io.quarkus.arc.impl.ArcContainerImpl.shutdown(ArcContainerImpl.java:468)
        at io.quarkus.arc.Arc.shutdown(Arc.java:66)
        at io.quarkus.arc.runtime.ArcRecorder$1.run(ArcRecorder.java:53)
        at io.quarkus.runtime.StartupContext.runAllInReverseOrder(StartupContext.java:84)
        at io.quarkus.runtime.StartupContext.close(StartupContext.java:73)
        at io.quarkus.runner.ApplicationImpl.doStop(Unknown Source)
        at io.quarkus.runtime.Application.stop(Application.java:208)
        at io.quarkus.runtime.Application.stop(Application.java:155)
        at io.quarkus.runtime.ApplicationLifecycleManager$ShutdownHookThread.run(ApplicationLifecycleManager.java:436)
Caused by: java.sql.SQLException: This pool is closed and does not handle any more connections!
        at io.agroal.pool.ConnectionPool.beforeAcquire(ConnectionPool.java:209)
        at io.agroal.pool.ConnectionPool.getConnection(ConnectionPool.java:235)
        at io.agroal.pool.DataSource.getConnection(DataSource.java:86)
        at io.quarkus.hibernate.orm.runtime.customized.QuarkusConnectionProvider.getConnection(QuarkusConnectionProvider.java:23)
        at org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:38)
        at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:113)
        ... 92 more

2023-07-05 13:57:12,581 ERROR [org.hib.sea.map.orm.boo.imp.HibernateOrmIntegrationBooterImpl] (Shutdown thread) HSEARCH800035: Unable to shut down Hibernate Search: %1$s [Error Occurred After Shutdown]: org.hibernate.search.util.common.SearchException: HSEARCH000520: Hibernate Search encountered failures during shutdown. Failures:

    Hibernate ORM mapping: 
        failures: 
          - Unable to acquire JDBC Connection [This pool is closed and does not handle any more connections!] [n/a]
        at org.hibernate.search.engine.reporting.spi.RootFailureCollector.checkNoFailure(RootFailureCollector.java:53)
        at org.hibernate.search.engine.common.impl.SearchIntegrationImpl.close(SearchIntegrationImpl.java:168)
        at org.hibernate.search.mapper.orm.mapping.impl.HibernateSearchContextProviderService.close(HibernateSearchContextProviderService.java:36)
        at org.hibernate.search.mapper.orm.bootstrap.impl.HibernateOrmIntegrationBooterImpl.lambda$orchestrateBootAndShutdown$5(HibernateOrmIntegrationBooterImpl.java:156)
        at java.base/java.util.concurrent.CompletableFuture.biAccept(CompletableFuture.java:1386)
        at java.base/java.util.concurrent.CompletableFuture$BiAccept.tryFire(CompletableFuture.java:1355)
        at java.base/java.util.concurrent.CompletableFuture$CoCompletion.tryFire(CompletableFuture.java:1219)
        at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
        at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147)
        at org.hibernate.search.mapper.orm.bootstrap.impl.HibernateSearchSessionFactoryObserver.sessionFactoryClosing(HibernateSearchSessionFactoryObserver.java:50)
        at org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryClosing(SessionFactoryObserverChain.java:48)
        at org.hibernate.internal.SessionFactoryImpl.close(SessionFactoryImpl.java:869)
        at io.quarkus.hibernate.orm.runtime.JPAConfig$LazyPersistenceUnit.close(JPAConfig.java:168)
        at io.quarkus.hibernate.orm.runtime.JPAConfig$Destroyer.destroy(JPAConfig.java:130)
        at io.quarkus.hibernate.orm.runtime.JPAConfig$Destroyer.destroy(JPAConfig.java:125)
        at io.quarkus.hibernate.orm.runtime.JPAConfig_b44400079827d7cae558c390d8d94cadbd711498_Synthetic_Bean.doDestroy(Unknown Source)
        at io.quarkus.hibernate.orm.runtime.JPAConfig_b44400079827d7cae558c390d8d94cadbd711498_Synthetic_Bean.destroy(Unknown Source)
        at io.quarkus.hibernate.orm.runtime.JPAConfig_b44400079827d7cae558c390d8d94cadbd711498_Synthetic_Bean.destroy(Unknown Source)
        at io.quarkus.arc.impl.AbstractInstanceHandle.destroyInternal(AbstractInstanceHandle.java:82)
        at io.quarkus.arc.impl.ContextInstanceHandleImpl.destroy(ContextInstanceHandleImpl.java:21)
        at io.quarkus.arc.impl.AbstractSharedContext.destroy(AbstractSharedContext.java:96)
        at io.quarkus.arc.impl.ArcContainerImpl.shutdown(ArcContainerImpl.java:468)
        at io.quarkus.arc.Arc.shutdown(Arc.java:66)
        at io.quarkus.arc.runtime.ArcRecorder$1.run(ArcRecorder.java:53)
        at io.quarkus.runtime.StartupContext.runAllInReverseOrder(StartupContext.java:84)
        at io.quarkus.runtime.StartupContext.close(StartupContext.java:73)
        at io.quarkus.runner.ApplicationImpl.doStop(Unknown Source)
        at io.quarkus.runtime.Application.stop(Application.java:208)
        at io.quarkus.runtime.Application.stop(Application.java:155)

How to Reproduce?

No response

Output of uname -a or ver

No response

Output of java -version

No response

GraalVM version (if different from Java)

No response

Quarkus version or git rev

No response

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

We should probably shut down Agroal after Hibernate ORM to avoid this exception.

@yrodiere yrodiere added the kind/bug Something isn't working label Jul 5, 2023
@quarkus-bot quarkus-bot bot added the area/hibernate-search Hibernate Search label Jul 5, 2023
@quarkus-bot
Copy link

quarkus-bot bot commented Jul 5, 2023

/cc @gsmet (hibernate-search)

@marko-bekhta
Copy link
Contributor

Hey @yrodiere
I've tried looking into this one, and from what it seems this is related to CDI more than to outbox polling and Hibernate Search. And it also looks like a more general problem. As you've suspected io.quarkus.agroal.runtime.DataSources sometimes gets closed sooner than the io.quarkus.hibernate.orm.runtime.JPAConfig leading to that exception.

We are adding an injection point:

// Add a synthetic dependency from JPAConfig to any datasource/pool,
// so that JPAConfig is destroyed before the datasource/pool.
// The alternative would be adding an application destruction observer
// (@Observes @BeforeDestroyed(ApplicationScoped.class)) to JPAConfig,
// but that would force initialization of JPAConfig upon application shutdown,
// which may cause cascading failures if the shutdown happened before JPAConfig was initialized.
if (capabilities.isPresent(Capability.HIBERNATE_REACTIVE)) {
configurator.addInjectionPoint(ParameterizedType.create(DotName.createSimple(Instance.class),
new Type[] { ClassType.create(DotName.createSimple("io.vertx.sqlclient.Pool")) }, null),
AnnotationInstance.builder(Any.class).build());
} else {
configurator.addInjectionPoint(ParameterizedType.create(DotName.createSimple(Instance.class),
new Type[] { ClassType.create(DotName.createSimple(DataSources.class)) }, null),
AnnotationInstance.builder(Any.class).build());
}

and based on the comment, we expect that the JPAConfig will get closed before the DataSources. I went through the Arc code a bit and didn't find that this would be "enforced" (but I also didn't want to spend too much time looking so maybe I've missed it 🙈)

To check this assumption, I've created two simple app-scoped beans (that is if my understanding was correct):

@ApplicationScoped
public class MyService1 {
    @Inject
    MyService2 service2;

    public String string() {
        return service2.string();
    }
    @PreDestroy
    public void destroy() {
        System.err.println("===========" + this.getClass().getName() + " destroy");
    }
}
@ApplicationScoped
public class MyService2 {

    public String string() {
        return "string2";
    }

    @PreDestroy
    public void destroy() {
        System.err.println("===========" + this.getClass().getName() + " destroy");
    }
}

and from time to time, MyService1 is closed before MyService2... But if I understand the assumption correctly, we'd expect that MyService2 is always closed before MyService1

I see that here, where the beans are destroyed (in the case of the JPAConfig and DataSources we are talking about the singleton context):

Set<ContextInstanceHandle<?>> values = instances.getAllPresent();
if (values.isEmpty()) {
return;
}
// Destroy the producers first
for (Iterator<ContextInstanceHandle<?>> it = values.iterator(); it.hasNext();) {
ContextInstanceHandle<?> instanceHandle = it.next();
if (instanceHandle.getBean().getDeclaringBean() != null) {
instanceHandle.destroy();
it.remove();
}
}
for (ContextInstanceHandle<?> instanceHandle : values) {
instanceHandle.destroy();
}
instances.removeEach(null);

we get a set of beans to destroy, and if we are "unlucky", DataSources are getting ahead of the JPAConfig in the iteration, and things fail: E.g.:

Destroy order io.quarkus.arc.impl.SingletonContext@1c231768:
class io.quarkus.agroal.runtime.DataSources						DeclaringBean: null
class io.quarkus.narayana.jta.runtime.NarayanaJtaProducers					DeclaringBean: CLASS bean [class=io.quarkus.narayana.jta.runtime.NarayanaJtaProducers, id=ol81PNK5K-jPtG8Wb8uxqBBB9cM]
class io.quarkus.arc.runtime.ConfigStaticInitValues					DeclaringBean: null
class io.quarkus.it.hibernate.search.orm.elasticsearch.coordination.outboxpolling.HibernateSearchOutboxPollingTestResource				 DeclaringBean: null
class io.quarkus.datasource.runtime.DataSourceSupport					DeclaringBean: null
class io.quarkus.hibernate.orm.runtime.cdi.QuarkusArcBeanContainer					DeclaringBean: null
class io.quarkus.hibernate.orm.runtime.JPAConfig					DeclaringBean: null
class io.quarkus.arc.runtime.LoggerProducer					DeclaringBean: null
class io.quarkus.narayana.jta.runtime.NarayanaJtaProducers					DeclaringBean: CLASS bean [class=io.quarkus.narayana.jta.runtime.NarayanaJtaProducers, id=ol81PNK5K-jPtG8Wb8uxqBBB9cM]

Neither JPAConfig nor DataSources have a DeclaringBean, hence DataSources are not destroyed in the first loop (with the // Destroy the producers first comment) and both are destroyed in the second one in the "random" order 😕

@yrodiere
Copy link
Member Author

Thanks for looking into this @marko-bekhta .

and based on the comment, we expect that the JPAConfig will get closed before the DataSources. I went through the Arc code a bit and didn't find that this would be "enforced" (but I also didn't want to spend too much time looking so maybe I've missed it 🙈)

@mkouba @Ladicek can you confirm that Arc beans are closed in an order that is consistent with the dependency graph -- at least when there is no cycle?
If not, can you please advise on the best way to ensure Arc beans get closed in a specific order?

FWIW, if closing order is not guaranteed, other issue may have the same root cause; see for example #36265 (comment)

@Ladicek
Copy link
Contributor

Ladicek commented Aug 14, 2024

There is no order in which beans are destroyed, and I believe there is no way to affect that.

I think @mkouba mentioned this several times: @PreDestroy listeners should be "local", that is, they should not expect other beans to exist. I believe observing the ShutdownEvent is a better choice in this regard -- when the observers run, it is guaranteed that the contexts still exist, and you can define observer priority (ordering).

@marko-bekhta
Copy link
Contributor

Thanks @Ladicek
I'll take a look at how we can update things then 🥲

@yrodiere
Copy link
Member Author

yrodiere commented Aug 14, 2024

Thanks.

Thanks @Ladicek I'll take a look at how we can update things then 🥲

@marko-bekhta I'm currently making changes in this area in #41929 ; see in particular https://github.com/quarkusio/quarkus/pull/41929/files#diff-ae22f0b05b345fab3d41e46504afedf53b79b6b3b4a12411bde2c8ae60c2c234L445-L453 and https://github.com/quarkusio/quarkus/pull/41929/files#diff-bc8502db2a346fd80de961c88ff8274ddfa740cdc9b462d33021d25cce7c452eR292.

You may want to wait until I'm done before you work on this? I'll probably be less likely to lead to conflicts. Can't promise when I'll be done though :/

I believe observing the ShutdownEvent is a better choice in this regard -- when the observers run, it is guaranteed that the contexts still exist, and you can define observer priority (ordering).

So I guess we could keep the existing @PreDestroy thing for Agroal, and shut down Hibernate ORM/Reactive with a ShutdownEvent observer? Which would guarantee that Hibernate ORM/Reactive shut down before Datasources.

For #36265 we basically want Agroal to shut down after Vertx... that probably means the Vertx extension needs to use ShutdownEvent? Maybe it already does, IDK.

@marko-bekhta
Copy link
Contributor

yeah, sure, I can wait 😃 no worries.

@mkouba
Copy link
Contributor

mkouba commented Aug 26, 2024

There is no order in which beans are destroyed, and I believe there is no way to affect that.

I think @mkouba mentioned this several times: @PreDestroy listeners should be "local", that is, they should not expect other beans to exist. I believe observing the ShutdownEvent is a better choice in this regard -- when the observers run, it is guaranteed that the contexts still exist, and you can define observer priority (ordering).

Correct. For @ApplicationScoped you can also consider an observer of @BeforeDestroyed(ApplicationScoped.class).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/hibernate-search Hibernate Search kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants