Skip to content

Commit 7b68188

Browse files
committed
Pass FailsafeExecutor.with(Executor) calls for ExecutorService instances
Part of issue #311
1 parent 422252b commit 7b68188

File tree

4 files changed

+48
-5
lines changed

4 files changed

+48
-5
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 3.0.2
2+
3+
### Bug Fixes
4+
5+
- Issue #311 - `with(Executor)` not working as expected in some cases.
6+
17
# 3.0.1
28

39
### Improvements

src/main/java/dev/failsafe/FailsafeExecutor.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -385,17 +385,26 @@ public FailsafeExecutor<R> with(ExecutorService executorService) {
385385
}
386386

387387
/**
388-
* Configures the {@code executor} to use as a wrapper around executions. The {@code executor} is responsible for
389-
* propagating executions. Executions that normally return a result, such as {@link #get(CheckedSupplier)} will return
390-
* {@code null} since the {@link Executor} interface does not support results.
388+
* Configures the {@code executor} to use as a wrapper around executions. If the {@code executor} is actually an
389+
* instance of {@link ExecutorService}, then the {@code executor} will be configured via {@link
390+
* #with(ExecutorService)} instead.
391+
* <p>
392+
* The {@code executor} is responsible for propagating executions. Executions that normally return a result, such as
393+
* {@link #get(CheckedSupplier)} will return {@code null} since the {@link Executor} interface does not support
394+
* results.
395+
* </p>
391396
* <p>The {@code executor} will not be used for {@link #getStageAsync(CheckedSupplier) getStageAsync} calls since
392397
* those require a returned result.
393398
* </p>
394399
*
395400
* @throws NullPointerException if {@code executor} is null
396401
*/
397402
public FailsafeExecutor<R> with(Executor executor) {
398-
this.executor = Assert.notNull(executor, "executor");
403+
Assert.notNull(executor, "executor");
404+
if (executor instanceof ExecutorService)
405+
with((ExecutorService) executor);
406+
else
407+
this.executor = executor;
399408
return this;
400409
}
401410

src/main/java/dev/failsafe/spi/Scheduler.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ static Scheduler of(ScheduledExecutorService scheduledExecutorService) {
4848
* Returns a Scheduler adapted from the {@code executorService}.
4949
*/
5050
static Scheduler of(ExecutorService executorService) {
51-
return new DelegatingScheduler(executorService);
51+
return executorService instanceof ScheduledExecutorService ?
52+
of((ScheduledExecutorService) executorService) :
53+
new DelegatingScheduler(executorService);
5254
}
5355
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package dev.failsafe.issues;
2+
3+
import dev.failsafe.Failsafe;
4+
import dev.failsafe.RetryPolicy;
5+
import org.testng.annotations.Test;
6+
7+
import java.util.concurrent.Executor;
8+
import java.util.concurrent.Executors;
9+
import java.util.concurrent.atomic.AtomicInteger;
10+
11+
import static org.testng.Assert.assertEquals;
12+
13+
public class Issue311Test {
14+
@Test
15+
void failsafeFail() throws Throwable {
16+
AtomicInteger counter = new AtomicInteger(0);
17+
Executor executor = Executors.newSingleThreadExecutor();
18+
Failsafe.with(RetryPolicy.builder().handle(RuntimeException.class).withMaxAttempts(2).build())
19+
.with(executor)
20+
.runAsync(() -> {
21+
if (counter.incrementAndGet() == 1)
22+
throw new RuntimeException();
23+
}).get();
24+
assertEquals(counter.get(), 2);
25+
}
26+
}

0 commit comments

Comments
 (0)