Skip to content

Can ListenableFuture.future() not unwrap CancellationException when needed? #4347

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

Open
ParafeniukMikalaj opened this issue Feb 10, 2025 · 1 comment

Comments

@ParafeniukMikalaj
Copy link

ParafeniukMikalaj commented Feb 10, 2025

Describe the bug

I have a piece of production code which uses ListenableFuture.future() to bridge the gap between blocking code and code using coroutines. In essence the code using coroutines does a few network requests and the blocking code uses ListenableFuture.future() followed by Future.get(). I have observed that Future.get() throws java.util.concurrent.CancellationException wrapping kotlinx.coroutines.JobCancellationException wrapping network exception. There is no explicit cancellations for the network calls and latencies are well below framework timeouts.

As far as I understand, Kotlin coroutines machinery should have unwrapped the CancellationException and Future.get() should have completed with ExecutionException wrapping the network errors. I checked ListenableFuture.future() code and it seems to me that CancellationException might not be unwrapped: JobListenableFuture receives cancellation exception and sets it as Canceled result to auxFuture (see JobListenableFuture.completeExceptionallyOrCancel()), when result is accessed it is converted back to CancellationException (see JobListenableFuture.getInternal())

Could it be the case that ListenableFuture.future() does not always correctly unwrap CancellationException?

Provide a Reproducer

Sorry, can't provide a reproducer but I am ready to answer additional questions.

@dkhalanskyjb
Copy link
Collaborator

dkhalanskyjb commented Feb 10, 2025

By ListenableFuture.future(), do you mean https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-guava/kotlinx.coroutines.guava/future.html ?

throws java.util.concurrent.CancellationException wrapping kotlinx.coroutines.JobCancellationException wrapping network exception

This means that some other coroutine in the same scope failed with a network exception, which caused this coroutine's scope to be cancelled, which cancelled the future. It would be incorrect to throw the network exception from Future.get() in this scenario: this coroutine didn't fail with a network exception, after all, it failed because some other coroutine did.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants