Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.time.Duration;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
Expand Down Expand Up @@ -163,25 +164,28 @@ private static <R> CompletableFuture<R> retryWithResultAsync(
.thenCompose(
(ignore) -> {
// try-catch is because get() call might throw.
CompletableFuture<R> result;
try {
CompletableFuture<R> result = function.get();
if (result == null) {
return CompletableFuture.completedFuture(null);
}
return result.handle(
(r, e) -> {
if (e == null) {
throttler.success();
return r;
} else {
throttler.failure();
throw CheckedExceptionWrapper.wrap(e);
}
});
result = function.get();
} catch (Throwable e) {
throttler.failure();
throw CheckedExceptionWrapper.wrap(e);
}

if (result == null) {
return CompletableFuture.completedFuture(null);
}

return result.handle(
(r, e) -> {
if (e == null) {
throttler.success();
return r;
} else {
throttler.failure();
throw CheckedExceptionWrapper.wrap(e);
}
});
})
.handle((r, e) -> failOrRetry(options, function, attempt, startTime, throttler, r, e))
.thenCompose(
Expand All @@ -205,9 +209,18 @@ private static <R> ValueExceptionPair<R> failOrRetry(
if (e == null) {
return new ValueExceptionPair<>(CompletableFuture.completedFuture(r), null);
}
//If exception is thrown from CompletionStage/CompletableFuture methods like compose or handle -
//it gets wrapped into CompletionException, so here we need to unwrap it.
// We can get not wrapped raw exception here too if CompletableFuture was explicitly
//filled with this exception using CompletableFuture.completeExceptionally
if (e instanceof CompletionException) {
e = e.getCause();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the fix

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you leave a comment explaining why we do what we do?
Also it's possible for CompletionException to be constructed without cause, should we still do this trick in that case?

Copy link
Contributor Author

@Spikhalskiy Spikhalskiy May 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you leave a comment explaining why we do what we do?

I added the comment, also there are tests for both wrapped and unwrapped exceptions added in this PR.

Also it's possible for CompletionException to be constructed without cause, should we still do this trick in that case?

It's kinda an illegal state. CompletionException is intended to be a wrapper over another exception. But it's technically possible and it will work correctly: The next if check will be true and we will return without retrying because GrpcRetrier retries only StatusRuntimeException.

}
// Do not retry if it's not StatusRuntimeException
if (!(e instanceof StatusRuntimeException)) {
return new ValueExceptionPair<>(null, e);
}

StatusRuntimeException exception = (StatusRuntimeException) e;
long elapsed = System.currentTimeMillis() - startTime;
for (RpcRetryOptions.DoNotRetryPair pair : options.getDoNotRetry()) {
Expand Down
269 changes: 0 additions & 269 deletions temporal-sdk/src/main/java/io/temporal/internal/common/Retryer.java

This file was deleted.

Loading