Skip to content

Commit

Permalink
feat: safe orTimeout* methods keep the direct TimeoutException in…
Browse files Browse the repository at this point in the history
…stead of `CompletionException` wrapper ⏳ ✨

consistent with `Cf.orTimeout` builtin method ✨
  • Loading branch information
oldratlee committed Jun 4, 2024
1 parent d029715 commit 5375f54
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 40 deletions.
10 changes: 0 additions & 10 deletions cffu-core/src/main/java/io/foldright/cffu/Cffu.java
Original file line number Diff line number Diff line change
Expand Up @@ -946,11 +946,6 @@ public Cffu<T> exceptionallyAsync(Function<Throwable, ? extends T> fn, Executor
* if not otherwise completed before the given timeout.
* <p>
* Uses {@link #defaultExecutor()} as {@code executorWhenTimeout}.
* <p>
* <strong>CAUTION:<br></strong>
* If the wait timed out, the returned Cffu complete exceptionally with a CompletionException holding
* the {@link TimeoutException} as its cause; NOT a direct {@link TimeoutException}
* like {@link #unsafeOrTimeout(long, TimeUnit)}/{@link CompletableFuture#orTimeout(long, TimeUnit)}.
*
* @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of {@code unit}
* @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter
Expand All @@ -964,11 +959,6 @@ public Cffu<T> orTimeout(long timeout, TimeUnit unit) {
/**
* Exceptionally completes this Cffu with a {@link TimeoutException}
* if not otherwise completed before the given timeout.
* <p>
* <strong>CAUTION:<br></strong>
* If the wait timed out, the returned Cffu complete exceptionally with a CompletionException holding
* the {@link TimeoutException} as its cause; NOT a direct {@link TimeoutException}
* like {@link #unsafeOrTimeout(long, TimeUnit)}/{@link CompletableFuture#orTimeout(long, TimeUnit)}.
*
* @param executorWhenTimeout the async executor when triggered by timeout
* @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of {@code unit}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1487,11 +1487,6 @@ C exceptionallyAsync(C cf, Function<Throwable, ? extends T> fn, Executor executo
* if not otherwise completed before the given timeout.
* <p>
* Uses CompletableFuture's default asynchronous execution facility as {@code executorWhenTimeout}.
* <p>
* <strong>CAUTION:<br></strong>
* If the wait timed out, the returned CompletableFuture complete exceptionally with a CompletionException holding
* the {@link TimeoutException} as its cause; NOT a direct {@link TimeoutException}
* like {@link #orTimeout(CompletableFuture, long, TimeUnit)}/{@link CompletableFuture#orTimeout(long, TimeUnit)}.
*
* @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of {@code unit}
* @param unit a {@code TimeUnit} determining how to interpret the {@code timeout} parameter
Expand All @@ -1505,11 +1500,6 @@ public static <C extends CompletableFuture<?>> C cffuOrTimeout(C cf, long timeou
/**
* Exceptionally completes given CompletableFuture with a {@link TimeoutException}
* if not otherwise completed before the given timeout.
* <p>
* <strong>CAUTION:<br></strong>
* If the wait timed out, the returned CompletableFuture complete exceptionally with a CompletionException holding
* the {@link TimeoutException} as its cause; NOT a direct {@link TimeoutException}
* like {@link #orTimeout(CompletableFuture, long, TimeUnit)}/{@link CompletableFuture#orTimeout(long, TimeUnit)}.
*
* @param executorWhenTimeout the async executor when triggered by timeout
* @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of {@code unit}
Expand Down Expand Up @@ -1646,17 +1636,20 @@ C completeOnTimeout(C cf, @Nullable T value, long timeout, TimeUnit unit) {

@SuppressWarnings("unchecked")
private static <C extends CompletableFuture<?>> C hopExecutorIfAtCfDelayerThread(C cf, Executor asyncExecutor) {
final CompletionStage<Object> f = (CompletionStage<Object>) cf;
CompletableFuture<Object> ret = newIncompleteFuture(cf);

return (C) f.handle((v, ex) -> null).thenCompose(unused -> {
if (!atCfDelayerThread()) return f;
cf.whenComplete((v, ex) -> {
if (!atCfDelayerThread()) completeCf(ret, v, ex);
else delayedExecutor(0, TimeUnit.SECONDS, asyncExecutor)
.execute(() -> completeCf(ret, v, ex));
});

CompletableFuture<Void> signal = new CompletableFuture<>();
delayedExecutor(0, TimeUnit.SECONDS, asyncExecutor)
.execute(() -> signal.complete(null));
return (C) ret;
}

return signal.thenCompose(v -> f);
});
private static void completeCf(CompletableFuture<Object> cf, Object value, @Nullable Throwable ex) {
if (ex == null) cf.complete(value);
else cf.completeExceptionally(ex);
}

//# Advanced methods of CompletionStage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1043,17 +1043,13 @@ void test_safeBehavior_orTimeout() {
}).join());

assertEquals(n, cffuOrTimeout(createIncompleteFuture(), 5, TimeUnit.MILLISECONDS).handle((r, ex) -> {
// FIXME: Not TimeoutException, not compatible with orTimeout method
assertInstanceOf(CompletionException.class, ex);
assertInstanceOf(TimeoutException.class, ex.getCause());
assertInstanceOf(TimeoutException.class, ex);
assertFalse(Delayer.atCfDelayerThread());
assertNotSame(testThread, currentThread());
return n;
}).join());
assertEquals(n, cffuOrTimeout(createIncompleteFuture(), executorService, 5, TimeUnit.MILLISECONDS).handle((r, ex) -> {
// FIXME: Not TimeoutException, not compatible with orTimeout method
assertInstanceOf(CompletionException.class, ex);
assertInstanceOf(TimeoutException.class, ex.getCause());
assertInstanceOf(TimeoutException.class, ex);
assertFalse(Delayer.atCfDelayerThread());
assertTrue(TestThreadPoolManager.isRunInExecutor(executorService));
return n;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -771,9 +771,6 @@ fun <T, C : CompletionStage<in T>> C.exceptionallyAsync(fn: Function<Throwable,
*
* Uses CompletableFuture's default asynchronous execution facility as `executorWhenTimeout`.
*
* **CAUTION:** If the wait timed out, the returned CompletableFuture complete exceptionally with a CompletionException
* holding the [TimeoutException] as its cause; NOT a direct [TimeoutException] like [orTimeout]/[CompletableFuture.orTimeout].
*
* @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of `unit`
* @param unit a `TimeUnit` determining how to interpret the `timeout` parameter
* @return the new CompletableFuture
Expand All @@ -785,9 +782,6 @@ fun <T, C : CompletableFuture<out T>> C.cffuOrTimeout(timeout: Long, unit: TimeU
* Exceptionally completes this CompletableFuture with a TimeoutException
* if not otherwise completed before the given timeout.
*
* **CAUTION:** If the wait timed out, the returned CompletableFuture complete exceptionally with a CompletionException
* holding the [TimeoutException] as its cause; NOT a direct [TimeoutException] like [orTimeout]/[CompletableFuture.orTimeout].
*
* @param executorWhenTimeout the async executor when triggered by timeout
* @param timeout how long to wait before completing exceptionally with a TimeoutException, in units of `unit`
* @param unit a `TimeUnit` determining how to interpret the `timeout` parameter
Expand Down

0 comments on commit 5375f54

Please sign in to comment.