quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.87k stars 2.71k forks source link

HttpClient Closed Prematurely Before @Shutdown Processing #39254

Open tibramo opened 9 months ago

tibramo commented 9 months ago

Describe the bug

I am using rest-client-reactive and resteasy-reactive. During shutdown, I attempt an HTTP request by annotating a method with @Shutdown. This method calls the API client and waits for its completion.

Expected behavior

The HTTP request succeeds, and the application subsequently shuts down.

Actual behavior

The HTTP client is prematurely closed and unable to process the request. A log message 'Running a shutdown task failed [Error Occurred After Shutdown]' is printed with the following stack trace:

java.lang.IllegalStateException: Client is closed
at io.vertx.core.http.impl.HttpClientImpl.checkClosed(HttpClientImpl.java:405)
at io.vertx.core.http.impl.HttpClientImpl.doRequest(HttpClientImpl.java:281)
at io.vertx.core.http.impl.HttpClientImpl.request(HttpClientImpl.java:184)
at org.jboss.resteasy.reactive.client.handlers.ClientSendRequestHandler$5.lambda$apply$0(ClientSendRequestHandler.java:434)
at io.smallrye.context.impl.wrappers.SlowContextualConsumer.accept(SlowContextualConsumer.java:21)
at org.jboss.resteasy.reactive.client.AsyncResultUni.subscribe(AsyncResultUni.java:31)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:81)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
at io.smallrye.mutiny.operators.uni.UniOnItemConsume$UniOnItemComsumeProcessor.onItem(UniOnItemConsume.java:43)
at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:43)
at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.forward(UniCreateFromKnownItem.java:38)
at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem.subscribe(UniCreateFromKnownItem.java:23)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniOnItemTransform.subscribe(UniOnItemTransform.java:22)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniOnItemConsume.subscribe(UniOnItemConsume.java:30)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni.subscribe(UniOnItemTransformToUni.java:25)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.groups.UniSubscribe.withSubscriber(UniSubscribe.java:51)
at io.smallrye.mutiny.groups.UniSubscribe.with(UniSubscribe.java:110)
at io.smallrye.mutiny.groups.UniSubscribe.with(UniSubscribe.java:88)
at org.jboss.resteasy.reactive.client.handlers.ClientSendRequestHandler.handle(ClientSendRequestHandler.java:94)
at org.jboss.resteasy.reactive.client.handlers.ClientSendRequestHandler.handle(ClientSendRequestHandler.java:66)
at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.invokeHandler(AbstractResteasyReactiveContext.java:231)
at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
at io.smallrye.context.impl.wrappers.SlowContextualRunnable.run(SlowContextualRunnable.java:19)
at org.jboss.resteasy.reactive.client.handlers.ClientSwitchToRequestContextRestHandler$1$1.handle(ClientSwitchToRequestContextRestHandler.java:38)
at org.jboss.resteasy.reactive.client.handlers.ClientSwitchToRequestContextRestHandler$1$1.handle(ClientSwitchToRequestContextRestHandler.java:35)
at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:276)
at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:258)
at io.vertx.core.impl.ContextInternal.lambda$runOnContext$0(ContextInternal.java:56)
at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:166)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:840)

How to Reproduce?

No response

Output of uname -a or ver

Linux xxx-xxx-xxx5.14.0-284.50.1.el9_2.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Jan 18 12:28:24 EST 2024 x86_64 x86_64 x86_64 GNU/Linux

Output of java -version

openjdk version "17.0.9" 2023-10-17

Quarkus version or git rev

3.8.1

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

Apache Maven 3.8.5 (Red Hat 3.8.5-4)

Additional information

I couldn't reproduce the issue locally, only with the deployed application on OpenShift. The error occurs only when a REST interface provided by the application has been called previously. If a freshly started pod is terminated, sending requests is successful. Through remote debugging, I observed that in case of an error, the HTTP client is closed by executing the closeTask of VertxHttpRecorder before the ShutdownEvent is fired by the ArcRecorder.

quarkus-bot[bot] commented 9 months ago

/cc @geoand (openshift), @iocanel (openshift)

geoand commented 6 months ago

I would suggest not using any managed code in @Shutdown code