Skip to content

Commit

Permalink
feat: report exception info of peek action, errors should never pass …
Browse files Browse the repository at this point in the history
…silently 💣 👀
  • Loading branch information
oldratlee committed Jun 3, 2024
1 parent 2901c4d commit 410a822
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 20 deletions.
12 changes: 6 additions & 6 deletions cffu-core/src/main/java/io/foldright/cffu/Cffu.java
Original file line number Diff line number Diff line change
Expand Up @@ -1319,8 +1319,8 @@ public Cffu<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action
* Peeks the result by executing the given action when this cffu completes, returns this cffu.
* <p>
* When this cffu is complete, the given action is invoked with the result (or {@code null} if none)
* and the exception (or {@code null} if none) of this cffu as arguments.
* Whether the supplied action throws an exception or not, do <strong>NOT</strong> affect this cffu.
* and the exception (or {@code null} if none) of this cffu as arguments. Whether the supplied action
* throws an exception or not, this cffu is <strong>NOT</strong> affected.
* <p>
* Unlike method {@link CompletionStage#handle handle} and like method
* {@link CompletionStage#whenComplete(BiConsumer) whenComplete},
Expand All @@ -1341,8 +1341,8 @@ public Cffu<T> peek(BiConsumer<? super T, ? super Throwable> action) {
* executes the given action using {@link #defaultExecutor()}, returns this cffu.
* <p>
* When this cffu is complete, the given action is invoked with the result (or {@code null} if none)
* and the exception (or {@code null} if none) of this cffu as arguments.
* Whether the supplied action throws an exception or not, do <strong>NOT</strong> affect this cffu.
* and the exception (or {@code null} if none) of this cffu as arguments. Whether the supplied action
* throws an exception or not, this cffu is <strong>NOT</strong> affected.
* <p>
* Unlike method {@link CompletionStage#handle handle} and like method
* {@link CompletionStage#whenComplete(BiConsumer) whenComplete},
Expand All @@ -1362,8 +1362,8 @@ public Cffu<T> peekAsync(BiConsumer<? super T, ? super Throwable> action) {
* that executes the given action using the supplied Executor when this cffu completes, returns this cffu.
* <p>
* When this cffu is complete, the given action is invoked with the result (or {@code null} if none)
* and the exception (or {@code null} if none) of this cffu as arguments.
* Whether the supplied action throws an exception or not, do <strong>NOT</strong> affect this cffu.
* and the exception (or {@code null} if none) of this cffu as arguments. Whether the supplied action
* throws an exception or not, this cffu is <strong>NOT</strong> affected.
* <p>
* Unlike method {@link CompletionStage#handle handle} and like method
* {@link CompletionStage#whenComplete(BiConsumer) whenComplete},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import org.jetbrains.annotations.Contract;

import javax.annotation.ParametersAreNonnullByDefault;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -1252,8 +1254,8 @@ public static <T, U> CompletableFuture<U> applyToEitherSuccessAsync(
* Peeks the result by executing the given action when given stage completes, returns the given stage.
* <p>
* When the given stage is complete, the given action is invoked with the result (or {@code null} if none)
* and the exception (or {@code null} if none) of given stage as arguments.
* Whether the supplied action throws an exception or not, do <strong>NOT</strong> affect this cffu.
* and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action
* throws an exception or not, the given stage is <strong>NOT</strong> affected.
* <p>
* Unlike method {@link CompletionStage#handle handle} and like method
* {@link CompletionStage#whenComplete(BiConsumer) whenComplete},
Expand All @@ -1269,7 +1271,7 @@ C peek(C cf, BiConsumer<? super T, ? super Throwable> action) {
requireNonNull(cf, "cf is null");
requireNonNull(action, "action is null");

cf.whenComplete(action);
cf.whenComplete(action).exceptionally(CompletableFutureUtils::reportExceptionInfoOfPeekAction);
return cf;
}

Expand All @@ -1279,8 +1281,8 @@ C peek(C cf, BiConsumer<? super T, ? super Throwable> action) {
* returns the given stage.
* <p>
* When the given stage is complete, the given action is invoked with the result (or {@code null} if none)
* and the exception (or {@code null} if none) of given stage as arguments.
* Whether the supplied action throws an exception or not, do <strong>NOT</strong> affect this cffu.
* and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action
* throws an exception or not, the given stage is <strong>NOT</strong> affected.
* <p>
* Unlike method {@link CompletionStage#handle handle} and like method
* {@link CompletionStage#whenComplete(BiConsumer) whenComplete},
Expand All @@ -1301,8 +1303,8 @@ C peekAsync(C cf, BiConsumer<? super T, ? super Throwable> action) {
* executes the given action using the supplied Executor, returns the given stage.
* <p>
* When the given stage is complete, the given action is invoked with the result (or {@code null} if none)
* and the exception (or {@code null} if none) of given stage as arguments.
* Whether the supplied action throws an exception or not, do <strong>NOT</strong> affect this cffu.
* and the exception (or {@code null} if none) of given stage as arguments. Whether the supplied action
* throws an exception or not, the given stage is <strong>NOT</strong> affected.
* <p>
* Unlike method {@link CompletionStage#handle handle} and like method
* {@link CompletionStage#whenComplete(BiConsumer) whenComplete},
Expand All @@ -1319,10 +1321,22 @@ C peekAsync(C cf, BiConsumer<? super T, ? super Throwable> action, Executor exec
requireNonNull(action, "action is null");
requireNonNull(executor, "executor is null");

cf.whenCompleteAsync(action, executor);
cf.whenCompleteAsync(action, executor).exceptionally(CompletableFutureUtils::reportExceptionInfoOfPeekAction);
return cf;
}

@Nullable
private static <T> T reportExceptionInfoOfPeekAction(Throwable ex) {
StringWriter sw = new StringWriter(4096);
PrintWriter writer = new PrintWriter(sw);

writer.println("Exception occurred in the action of peek:");
ex.printStackTrace(writer);

System.err.println(sw);
return null;
}

////////////////////////////////////////////////////////////////////////////////
//# Backport CF static methods + related enhanced methods
// compatibility for low Java versions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package io.foldright.cffu.kotlin
import io.foldright.cffu.Cffu
import io.foldright.cffu.CffuState
import io.foldright.cffu.CompletableFutureUtils
import java.util.*
import java.util.concurrent.*
import java.util.function.*
import java.util.function.Function
Expand Down Expand Up @@ -655,8 +656,8 @@ fun <T, U> CompletionStage<out T>.applyToEitherSuccessAsync(
* Peeks the result by executing the given action when this stage completes, returns this stage.
*
* When this stage is complete, the given action is invoked with the result (or `null` if none)
* and the exception (or `null` if none) of this stage as arguments.
* Whether the supplied action throws an exception or not, do **NOT** affect this cffu.
* and the exception (or `null` if none) of given stage as arguments. Whether the supplied action
* throws an exception or not, this stage is **NOT** affected.
*
* Unlike method [handle][CompletionStage.handle] and like method [whenComplete][CompletionStage.whenComplete],
* this method is not designed to translate completion outcomes.
Expand All @@ -674,8 +675,8 @@ fun <T, C : CompletionStage<out T>> C.peek(action: BiConsumer<in T, in Throwable
* executes the given action using this stage's default asynchronous execution facility, returns this stage.
*
* When this stage is complete, the given action is invoked with the result (or `null` if none)
* and the exception (or `null` if none) of this stage as arguments.
* Whether the supplied action throws an exception or not, do **NOT** affect this cffu.
* and the exception (or `null` if none) of given stage as arguments. Whether the supplied action
* throws an exception or not, this stage is **NOT** affected.
*
* Unlike method [handle][CompletionStage.handle] and like method [whenComplete][CompletionStage.whenComplete],
* this method is not designed to translate completion outcomes.
Expand All @@ -693,8 +694,8 @@ fun <T, C : CompletionStage<out T>> C.peekAsync(action: BiConsumer<in T, in Thro
* executes the given action using the supplied Executor, returns this stage.
*
* When this stage is complete, the given action is invoked with the result (or `null` if none)
* and the exception (or `null` if none) of this stage as arguments.
* Whether the supplied action throws an exception or not, do **NOT** affect this cffu.
* and the exception (or `null` if none) of given stage as arguments. Whether the supplied action
* throws an exception or not, this stage is **NOT** affected.
*
* Unlike method [handle][CompletionStage.handle] and like method [whenComplete][CompletionStage.whenComplete],
* this method is not designed to translate completion outcomes.
Expand Down

0 comments on commit 410a822

Please sign in to comment.