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

quarkus-rest-client: java.io.IOException: Connection was closed invoking async endpoint #43792

Closed
nicolasduminil opened this issue Oct 9, 2024 · 6 comments
Labels
area/rest-client kind/question Further information is requested

Comments

@nicolasduminil
Copy link

nicolasduminil commented Oct 9, 2024

Describe the bug

In a Quarkus 3.15 web service I have the following REST endpoint:

  ...
  @POST
  public void doSomething (SomeDTO someDTO, @Suspended AsyncResponse ar)
  {
    ar.resume(Response.created(...) .build());
  }
  ...

The associated MP REST Client interface is:

  ...
  @POST
  CompletionStage<Response> doSomething(SomeDTO someDTO);
  ...

And the client invocation:

  ...
  @Inject
  @RestClient
  SomeClient someClient;
  ...
  someClient.doSomething(someDto)
    .thenAccept(response ->
    {
       ...
    })
    .toCompletableFuture()
    .exceptionally(ex -> {
      ex.printStackTrace();
      ...
    }); 
    ...

Expected behavior

I expect that the code above works.

Actual behavior

Actually it doesn't and raises the following exception in the exceptionally section:

java.util.concurrent.CompletionException: jakarta.ws.rs.ProcessingException: java.io.IOException: Connection was closed
    at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:332)
    at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:347)
    at java.base/java.util.concurrent.CompletableFuture$UniAccept.tryFire(CompletableFuture.java:708)
    at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
    at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2194)
    at org.jboss.resteasy.reactive.client.handlers.ClientErrorHandler.handle(ClientErrorHandler.java:27)
    at org.jboss.resteasy.reactive.client.handlers.ClientErrorHandler.handle(ClientErrorHandler.java:11)
    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:279)
    at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:261)
    at io.vertx.core.impl.ContextInternal.lambda$runOnContext$0(ContextInternal.java:59)
    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:469)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:994)
    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)
  ...

I presume that this happens because, at the time that the new thread is created, the connection is already closed, or something similar. How could I fix that ?

Many thanks in advance.

How to Reproduce?

I don't have a reproducer but I could provide one, if required.

Output of uname -a or ver

Linux nicolas-XPS-15-9570 6.8.0-45-generic #45-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug 30 12:02:04 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

Output of java -version

java version "21.0.3" 2024-04-16 LTS Java(TM) SE Runtime Environment (build 21.0.3+7-LTS-152) Java HotSpot(TM) 64-Bit Server VM (build 21.0.3+7-LTS-152, mixed mode, sharing)

Quarkus version or git rev

3.15.1

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

Apache Maven 3.9.5 (57804ffe001d7215b5e7bcb531cf83df38f93546) Maven home: /opt/apache-maven-3.9.5 Java version: 21.0.3, vendor: Oracle Corporation, runtime: /usr/lib/jvm/jdk-21-oracle-x64 Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "6.8.0-45-generic", arch: "amd64", family: "unix

Additional information

I've already experienced a similar issue (#42764), but it was in the context of using the JAX-RS client with Loom.

@nicolasduminil nicolasduminil added the kind/bug Something isn't working label Oct 9, 2024
Copy link

quarkus-bot bot commented Oct 9, 2024

/cc @cescoffier (rest-client), @geoand (rest-client)

@nicolasduminil nicolasduminil changed the title quarkus-rest-client: java.io.IOException: Connection was closed invoking async endpoint with quarkus-rest-client: java.io.IOException: Connection was closed invoking async endpoint Oct 9, 2024
@geoand
Copy link
Contributor

geoand commented Oct 14, 2024

Thanks for reporting!

Any chance you can put together a sample application which we can use to trivially see the problem in action?
I am not sure what's going on, so we'll need a way to reliably reproduce it in order to probe the code and see where the issue is.

@geoand geoand added the triage/needs-reproducer We are waiting for a reproducer. label Oct 14, 2024
@nicolasduminil
Copy link
Author

@geoand : Sure, here. To reproduce:

$ git clone https://github.com/nicolasduminil/quarkus-test-case.git
$ cd quarkus-test-case
$ mvn package failsafe:integration-test

There are 3 unit tests, using RESTassured, that pass and an integration test, using quarkus-rest-client, that doesn't and raises the mentioned exception.

So basically, I'm not sure that, given a REST endpoint like this:

  @POST
  public void postCurrentDateAndTime(@Suspended AsyncResponse ar)
  ...

its associated MP REST Client interface should be:

  @POST
  CompletionStage<Response> postCurrentDateAndTime();

If it is, why do I get this exception ? If it isn't, how should then the interface be defined such that to match with the endpoint ?

@geoand geoand removed the triage/needs-reproducer We are waiting for a reproducer. label Oct 15, 2024
@geoand
Copy link
Contributor

geoand commented Oct 15, 2024

The reason that you are seeing this behavior in the tests is because when you do:

CompletionStage<Void> currentDateAndTime = timeResourceClient.postCurrentDateAndTime()

...

you are not actually waiting for the result, you are simply obtaining a "promise" that a result will at some point become available.
Because you not waiting for the result, the application then is closed when the test finishes and you get the exception.

This can be fixed very simply by adding:

currentDateAndTime.toCompletableFuture().join();

@geoand geoand closed this as completed Oct 15, 2024
@geoand geoand added kind/question Further information is requested and removed kind/bug Something isn't working labels Oct 15, 2024
@nicolasduminil
Copy link
Author

Thanks

@geoand
Copy link
Contributor

geoand commented Oct 15, 2024

👌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/rest-client kind/question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants