quarkus: ResponseExceptionMapper is not invoked on `java.net.ConnectException: Connection refused`

Describe the bug

I wrote a ResponseExceptionMapper (in Kotlin) and it looks it works fine, but when the other service I want to access is not running at all, a java.net.ConnectException: Connection refused is thrown but doesn’t pass to the toThrowable function.

Expected behavior

It should be received inside the toThrowable function

https://github.com/Shinigami92/quarkus-fruits/blob/8a198bd6b805a7841537166e0381399d5421f18b/src/main/kotlin/com/github/shinigami92/OtherService.kt#L30-L34

Actual behavior

Nothing happens and the default handling applies

{
    "details": "Error id 486e5e50-a7db-4d6b-8922-02dd4f34d89e-2, javax.ws.rs.ProcessingException: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: localhost/127.0.0.1:8079",
    "stack": "javax.ws.rs.ProcessingException: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: localhost/127.0.0.1:8079
    at org.jboss.resteasy.reactive.client.handlers.ClientSendRequestHandler$3.accept(ClientSendRequestHandler.java:217)
    at org.jboss.resteasy.reactive.client.handlers.ClientSendRequestHandler$3.accept(ClientSendRequestHandler.java:209)
    at io.smallrye.context.impl.wrappers.SlowContextualConsumer.accept(SlowContextualConsumer.java:21)
    at io.smallrye.mutiny.helpers.UniCallbackSubscriber.onFailure(UniCallbackSubscriber.java:62)
    at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:55)
    at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:55)
    at org.jboss.resteasy.reactive.client.AsyncResultUni.lambda$subscribe$1(AsyncResultUni.java:37)
    at io.vertx.core.impl.future.FutureImpl$3.onFailure(FutureImpl.java:153)
    at io.vertx.core.impl.future.FutureBase.lambda$emitFailure$1(FutureBase.java:69)
    at io.vertx.core.impl.EventLoopContext.execute(EventLoopContext.java:86)
    at io.vertx.core.impl.DuplicatedContext.execute(DuplicatedContext.java:163)
    at io.vertx.core.impl.future.FutureBase.emitFailure(FutureBase.java:66)
    at io.vertx.core.impl.future.FutureImpl.tryFail(FutureImpl.java:230)
    at io.vertx.core.impl.future.PromiseImpl.tryFail(PromiseImpl.java:23)
    at io.vertx.core.http.impl.HttpClientImpl.lambda$doRequest$6(HttpClientImpl.java:658)
    at io.vertx.core.net.impl.pool.Endpoint.lambda$getConnection$0(Endpoint.java:52)
    at io.vertx.core.http.impl.SharedClientHttpStreamEndpoint$Request.handle(SharedClientHttpStreamEndpoint.java:162)
    at io.vertx.core.http.impl.SharedClientHttpStreamEndpoint$Request.handle(SharedClientHttpStreamEndpoint.java:123)
    at io.vertx.core.impl.EventLoopContext.emit(EventLoopContext.java:55)
    at io.vertx.core.impl.ContextBase.emit(ContextBase.java:239)
    at io.vertx.core.net.impl.pool.SimpleConnectionPool$ConnectFailed$1.run(SimpleConnectionPool.java:384)
    at io.vertx.core.net.impl.pool.CombinerExecutor.submit(CombinerExecutor.java:50)
    at io.vertx.core.net.impl.pool.SimpleConnectionPool.execute(SimpleConnectionPool.java:245)
    at io.vertx.core.net.impl.pool.SimpleConnectionPool.lambda$connect$2(SimpleConnectionPool.java:259)
    at io.vertx.core.http.impl.SharedClientHttpStreamEndpoint.lambda$connect$2(SharedClientHttpStreamEndpoint.java:104)
    at io.vertx.core.impl.future.FutureImpl$3.onFailure(FutureImpl.java:153)
    at io.vertx.core.impl.future.FutureBase.emitFailure(FutureBase.java:75)
    at io.vertx.core.impl.future.FutureImpl.tryFail(FutureImpl.java:230)
    at io.vertx.core.impl.future.Composition$1.onFailure(Composition.java:66)
    at io.vertx.core.impl.future.FutureBase.emitFailure(FutureBase.java:75)
    at io.vertx.core.impl.future.FailedFuture.addListener(FailedFuture.java:98)
    at io.vertx.core.impl.future.Composition.onFailure(Composition.java:55)
    at io.vertx.core.impl.future.FutureBase.emitFailure(FutureBase.java:75)
    at io.vertx.core.impl.future.FutureImpl.tryFail(FutureImpl.java:230)
    at io.vertx.core.impl.future.PromiseImpl.tryFail(PromiseImpl.java:23)
    at io.vertx.core.impl.EventLoopContext.emit(EventLoopContext.java:55)
    at io.vertx.core.impl.ContextBase.emit(ContextBase.java:239)
    at io.vertx.core.net.impl.NetClientImpl.failed(NetClientImpl.java:320)
    at io.vertx.core.net.impl.NetClientImpl.lambda$connectInternal2$5(NetClientImpl.java:288)
    at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:590)
    at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:557)
    at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:492)
    at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:636)
    at io.netty.util.concurrent.DefaultPromise.setFailure0(DefaultPromise.java:629)
    at io.netty.util.concurrent.DefaultPromise.setFailure(DefaultPromise.java:110)
    at io.vertx.core.net.impl.ChannelProvider.lambda$handleConnect$0(ChannelProvider.java:160)
    at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:590)
    at io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:583)
    at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:559)
    at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:492)
    at io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:636)
    at io.netty.util.concurrent.DefaultPromise.setFailure0(DefaultPromise.java:629)
    at io.netty.util.concurrent.DefaultPromise.tryFailure(DefaultPromise.java:118)
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.fulfillConnectPromise(AbstractNioChannel.java:321)
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:337)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:776)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
    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:1589)
Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: localhost/127.0.0.1:8079
Caused by: java.net.ConnectException: Connection refused
    at java.base/sun.nio.ch.Net.pollConnect(Native Method)
    at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672)
    at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:973)
    at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:337)
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:776)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
    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:1589)"
}

How to Reproduce?

https://github.com/Shinigami92/quarkus-fruits/blob/main/src/main/kotlin/com/github/shinigami92/OtherService.kt#L30-L34

git clone git@github.com:Shinigami92/quarkus-fruits.git
cd quarkus-fruits
quarkus dev

GET http://localhost:8080/api/fruit/other

profit $$$

Output of uname -a or ver

Darwin Shinigami-MBP.dermalog.hh 22.2.0 Darwin Kernel Version 22.2.0: Fri Nov 11 02:03:51 PST 2022; root:xnu-8792.61.2~4/RELEASE_ARM64_T6000 arm64

Output of java -version

openjdk version “19.0.1” 2022-10-18

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.15.2.Final

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

mvn via quarkus

Additional information

https://mas.to/@Shini92/109664368712090615

About this issue

  • Original URL
  • State: open
  • Created a year ago
  • Comments: 15 (10 by maintainers)

Most upvoted comments

It’s not exactly deprecated yet (I would say that it’s in maintenance mode), but we probably should do that, cc @maxandersen @cescoffier @gsmet

Yes, the quarkus-rest-client-reactive can be used in a blocking manner in the exact same way as you used the quarkus-rest-client. You only use reactive features if you want to.

For this reason (among others), this is the REST client we are focusing all our attention on.

If I remember correctly, the relevent code is on the RESTEasy side.

Unfortunately, there is no way to implement a custom handler for this case. I have the same problem because I want to handle it for Tracing.

I would likely implement such a capability to serve Tracing, which everyone could use, but I haven’t started that work yet.

I agree there should be a better to handle it that exists currently, I am just saying that ResponseExceptionMapper is likely not it.