Skip to content

quarkus-rest-client throws Timeoutexception on eventloop #45250

Open
@Postremus

Description

Describe the bug

I want to execute a http request in a prematching filter.
Since I can't block the event loop directly, I decided to do something like this:

try {

            Client client = ClientBuilder.newClient();
            WebTarget httpTarget = client.target(uri);
            String result = ((CompletableFuture<Response>) httpTarget.request().async().get()).thenApply(resp -> resp.readEntity(String.class))
                                                                                              .get(1, TimeUnit.SECONDS);
            Log.info(result);
        } catch (Exception e) {
            Log.error("",e);
        }

Which, In my mind, should execute the http request on a worker thread, and after the timeout return to the event loop.
The request normally takes 50ms, the timeout is there to make sure the thread is never blocked for too long.

However, this is not happening. I always get a TimeoutException. See below.

I also tried the same using a jdk http client.

try {
            HttpClient client = HttpClient.newHttpClient();
            HttpRequest request = HttpRequest.newBuilder().uri(uri).build();
            String result = client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body).get(1, TimeUnit.SECONDS);

            Log.info(result);
        } catch (Exception e) {
            Log.error("",e);
        }

This correctly prints the info log.

I am okay with the jdk client solution in this case. So this bug a report is more for documenting my findings, and asking: why is this happening?

Expected behavior

JDK and Quarkus rest client should work

Actual behavior

Only jdk client works.
rest client throws:

2024-12-23 10:43:47,021 ERROR [org.acm.MyResource] (vert.x-eventloop-thread-1) : java.util.concurrent.TimeoutException
        at java.base/java.util.concurrent.CompletableFuture.timedGet(CompletableFuture.java:1960)
        at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2095)
        at org.acme.MyResource.filterRc(MyResource.java:60)
        at org.acme.MyResource_ClientProxy.filterRc(Unknown Source)
        at org.acme.MyResource$GeneratedServerRequestFilter$filterRc.filter(Unknown Source)
        at org.acme.MyResource$GeneratedServerRequestFilter$filterRc_ClientProxy.filter(Unknown Source)
        at org.jboss.resteasy.reactive.server.handlers.ResourceRequestFilterHandler.handle(ResourceRequestFilterHandler.java:48)
        at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:131)
        at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
        at org.jboss.resteasy.reactive.server.handlers.RestInitialHandler.beginProcessing(RestInitialHandler.java:48)
        at org.jboss.resteasy.reactive.server.vertx.ResteasyReactiveVertxHandler.handle(ResteasyReactiveVertxHandler.java:23)
        at org.jboss.resteasy.reactive.server.vertx.ResteasyReactiveVertxHandler.handle(ResteasyReactiveVertxHandler.java:10)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1281)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:145)
        at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:62)
        at io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers$1.handle(HttpServerCommonHandlers.java:40)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1281)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:145)
        at io.quarkus.resteasy.reactive.server.runtime.ResteasyReactiveRecorder$13.handle(ResteasyReactiveRecorder.java:359)
        at io.quarkus.resteasy.reactive.server.runtime.ResteasyReactiveRecorder$13.handle(ResteasyReactiveRecorder.java:348)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1281)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:145)
        at io.quarkus.vertx.http.runtime.filters.accesslog.AccessLogHandler.handle(AccessLogHandler.java:164)
        at io.quarkus.vertx.http.runtime.filters.accesslog.AccessLogHandler.handle(AccessLogHandler.java:94)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1281)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:145)
        at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$5.handle(VertxHttpHotReplacementSetup.java:204)
        at io.quarkus.vertx.http.runtime.devmode.VertxHttpHotReplacementSetup$5.handle(VertxHttpHotReplacementSetup.java:192)
        at io.vertx.core.impl.future.FutureImpl$4.onSuccess(FutureImpl.java:176)
        at io.vertx.core.impl.future.FutureBase.lambda$emitSuccess$0(FutureBase.java:60)
        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:472)
        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:1583)

How to Reproduce?

Reproducer: asy-cf-rc.zip

  1. unzip, mvn clean compile quarkus:dev
  2. Call http://localhost:8080/rc. This throws an timeoutexception
  3. Call http://localhost:8080/jdk. This prints the info log

Output of uname -a or ver

MINGW64_NT-10.0-19045 NANBCHL9NG3 3.3.6-341.x86_64 2022-09-05 20:28 UTC x86_64 Msys

Output of java -version

openjdk 21.0.5 2024-10-15 LTS OpenJDK Runtime Environment Temurin-21.0.5+11 (build 21.0.5+11-LTS) OpenJDK 64-Bit Server VM Temurin-21.0.5+11 (build 21.0.5+11-LTS, mixed mode, sharing)

Quarkus version or git rev

3.17.5

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

Apache Maven 3.8.8 (4c87b05d9aedce574290d1acc98575ed5eb6cd39) Maven home: C:\eclipse\tools\java\maven Java version: 21.0.5, vendor: Eclipse Adoptium, runtime: C:\eclipse\tools\java\21 Default locale: de_DE, platform encoding: UTF-8 OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

Additional information

No response

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions