Skip to content

Commit cb95441

Browse files
authored
Add support for configurable Executor implementations (#281)
1 parent 167e5d4 commit cb95441

File tree

4 files changed

+71
-4
lines changed

4 files changed

+71
-4
lines changed

src/main/java/net/jodah/failsafe/FailsafeExecutor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ public FailsafeExecutor<R> with(ScheduledExecutorService executor) {
345345
*
346346
* @throws NullPointerException if {@code executor} is null
347347
*/
348-
public FailsafeExecutor<R> with(ExecutorService executor) {
348+
public FailsafeExecutor<R> with(Executor executor) {
349349
this.scheduler = Scheduler.of(executor);
350350
return this;
351351
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package net.jodah.failsafe.internal.util;
2+
3+
import java.util.List;
4+
import java.util.concurrent.*;
5+
6+
/**
7+
* Delegates executions to an underlying {@link Executor}.
8+
*/
9+
public class DelegatingExecutorService extends AbstractExecutorService {
10+
private final Executor executor;
11+
12+
public DelegatingExecutorService(Executor executor) {
13+
this.executor = executor;
14+
}
15+
16+
@Override
17+
public void shutdown() {
18+
}
19+
20+
@Override
21+
public List<Runnable> shutdownNow() {
22+
return null;
23+
}
24+
25+
@Override
26+
public boolean isShutdown() {
27+
return false;
28+
}
29+
30+
@Override
31+
public boolean isTerminated() {
32+
return false;
33+
}
34+
35+
@Override
36+
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
37+
return false;
38+
}
39+
40+
@Override
41+
public void execute(Runnable command) {
42+
executor.execute(command);
43+
}
44+
}

src/main/java/net/jodah/failsafe/util/concurrent/Scheduler.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package net.jodah.failsafe.util.concurrent;
1717

1818
import net.jodah.failsafe.internal.util.Assert;
19+
import net.jodah.failsafe.internal.util.DelegatingExecutorService;
1920
import net.jodah.failsafe.internal.util.DelegatingScheduler;
2021

2122
import java.util.concurrent.*;
@@ -53,7 +54,11 @@ static Scheduler of(final ScheduledExecutorService executor) {
5354
*
5455
* @throws NullPointerException if {@code executor} is null
5556
*/
56-
static Scheduler of(final ExecutorService executor) {
57-
return new DelegatingScheduler(Assert.notNull(executor, "executor"));
57+
static Scheduler of(final Executor executor) {
58+
Assert.notNull(executor, "executor");
59+
ExecutorService executorService = executor instanceof ExecutorService ?
60+
(ExecutorService) executor :
61+
new DelegatingExecutorService(executor);
62+
return new DelegatingScheduler(executorService);
5863
}
5964
}

src/test/java/net/jodah/failsafe/AsyncExecutionTest.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package net.jodah.failsafe;
1717

18+
import net.jodah.failsafe.Testing.Stats;
19+
import net.jodah.failsafe.Testing.SyncExecutor;
1820
import net.jodah.failsafe.util.concurrent.Scheduler;
1921
import org.testng.annotations.BeforeMethod;
2022
import org.testng.annotations.Test;
@@ -24,6 +26,8 @@
2426
import java.util.concurrent.Callable;
2527
import java.util.concurrent.TimeUnit;
2628

29+
import static net.jodah.failsafe.Testing.testAsyncFailure;
30+
import static net.jodah.failsafe.Testing.withStats;
2731
import static org.mockito.Mockito.*;
2832
import static org.testng.Assert.*;
2933

@@ -185,7 +189,7 @@ public void testRetryOn() {
185189
// Given rpRetry on IllegalArgumentException
186190
exec = new AsyncExecution(scheduler, future,
187191
executorFor(new RetryPolicy<>().handle(IllegalArgumentException.class)));
188-
exec.inject(Functions.getPromise(ctx-> null, exec), true);
192+
exec.inject(Functions.getPromise(ctx -> null, exec), true);
189193

190194
// When / Then
191195
assertTrue(exec.retryOn(new IllegalArgumentException()));
@@ -250,6 +254,20 @@ public void testCompleteOrRetry() {
250254
verify(future).completeResult(ExecutionResult.NONE);
251255
}
252256

257+
public void testExecutor() {
258+
Stats rpStats = new Stats();
259+
RetryPolicy<Object> rp = withStats(new RetryPolicy<>(), rpStats, false);
260+
261+
testAsyncFailure(Failsafe.with(rp).with(new SyncExecutor()), () -> {
262+
throw new IllegalStateException();
263+
}, e -> {
264+
assertEquals(e.getAttemptCount(), 3);
265+
assertEquals(e.getExecutionCount(), 3);
266+
assertEquals(rpStats.failedAttemptCount, 3);
267+
assertEquals(rpStats.retryCount, 2);
268+
}, IllegalStateException.class);
269+
}
270+
253271
@SuppressWarnings("unchecked")
254272
private void resetMocks() {
255273
reset(scheduler);

0 commit comments

Comments
 (0)