Description
Describe the bug
We are debugging an issue where code that uses Guava's SimpleTimeLimiter doesn't work properly when a process times out and as part of its cleanup closes an AWS SDK client that uses Netty as the HTTP implementation.
The reason seems to be that the AwaitCloseChannelPoolMap#close
implementation catches InterruptedException
and wraps it in RuntimeException
, hiding it from the calling code. This happens here:
Regression Issue
- Select this option if this issue appears to be a regression.
Expected Behavior
When a thread is interrupted it should either re-throw the InterruptedException
or mark the thread as interrupted with Thread.currentThread().interrupt()
, but not both mark the thread as interrupted and throw an exception. Throwing an generic exception means that other code that expects to either get interrupted, or to handle InterruptedException
to do cleanup instead sees an exception they don't understand.
Current Behavior
The thread marks the thread as interrupted and throws a generic RuntimeException
.
Reproduction Steps
I'm not able to reproduce it in isolation, but here is a stack trace showing how an InterruptedException
from CompletableFuture#get
is wrapped as a RuntimeException
by AwaitCloseChannelPoolMap#close
:
java.lang.RuntimeException: java.lang.InterruptedException
at software.amazon.awssdk.http.nio.netty.internal.AwaitCloseChannelPoolMap.close(AwaitCloseChannelPoolMap.java:175)
at software.amazon.awssdk.http.nio.netty.internal.utils.NettyUtils.runAndLogError(NettyUtils.java:386)
at software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient.close(NettyNioAsyncHttpClient.java:198)
at software.amazon.awssdk.utils.IoUtils.closeQuietly(IoUtils.java:70)
at software.amazon.awssdk.utils.IoUtils.closeIfCloseable(IoUtils.java:87)
at software.amazon.awssdk.utils.AttributeMap.closeIfPossible(AttributeMap.java:678)
at software.amazon.awssdk.utils.AttributeMap.access$1600(AttributeMap.java:49)
at software.amazon.awssdk.utils.AttributeMap$DerivedValue.close(AttributeMap.java:632)
at java.util.HashMap$Values.forEach(HashMap.java:1065)
at software.amazon.awssdk.utils.AttributeMap.close(AttributeMap.java:107)
at software.amazon.awssdk.core.client.config.SdkClientConfiguration.close(SdkClientConfiguration.java:118)
at software.amazon.awssdk.core.internal.http.HttpClientDependencies.close(HttpClientDependencies.java:82)
at software.amazon.awssdk.core.internal.http.AmazonAsyncHttpClient.close(AmazonAsyncHttpClient.java:75)
at software.amazon.awssdk.core.internal.handler.BaseAsyncClientHandler.close(BaseAsyncClientHandler.java:254)
at software.amazon.awssdk.services.athena.DefaultAthenaAsyncClient.close(DefaultAthenaAsyncClient.java:4906)
(redacted)
at java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.lang.Thread.run(Thread.java:840)
Caused by: java.lang.InterruptedException
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:386)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2096)
at software.amazon.awssdk.http.nio.netty.internal.AwaitCloseChannelPoolMap.close(AwaitCloseChannelPoolMap.java:172)
Possible Solution
Either call Thread.currentThread().interrupt()
and don't throw an exception, or re-throw the InterruptedException
(this would however require adding InterruptedException
to the method signature).
Additional Information/Context
No response
AWS Java SDK version used
2.27.21
JDK version used
Multiple
Operating System and version
Multiple