4747import java .util .concurrent .Future ;
4848import java .util .concurrent .RejectedExecutionException ;
4949import java .util .concurrent .ScheduledExecutorService ;
50- import java .util .concurrent .TimeUnit ;
51- import org .junit .jupiter .api .AfterEach ;
5250import org .junit .jupiter .api .Test ;
53- import org .junit .jupiter .params .ParameterizedTest ;
54- import org .junit .jupiter .params .provider .MethodSource ;
5551import org .mockito .Mockito ;
5652
5753class ScheduledRetryingExecutorTest extends AbstractRetryingExecutorTest {
58- private ScheduledExecutorService scheduler = Executors .newSingleThreadScheduledExecutor ();
5954
6055 // Number of test runs, essential for multithreaded tests.
6156 private static final int EXECUTIONS_COUNT = 5 ;
6257
6358 @ Override
6459 protected RetryingExecutorWithContext <String > getExecutor (RetryAlgorithm <String > retryAlgorithm ) {
65- return getRetryingExecutor (retryAlgorithm , scheduler );
60+ return getRetryingExecutor (retryAlgorithm , scheduledExecutorService );
6661 }
6762
6863 @ Override
@@ -78,30 +73,24 @@ private RetryingExecutorWithContext<String> getRetryingExecutor(
7873 return new ScheduledRetryingExecutor <>(retryAlgorithm , scheduler );
7974 }
8075
81- @ AfterEach
82- void after () {
83- scheduler .shutdownNow ();
84- }
85-
8676 @ Test
8777 void testSuccessWithFailuresPeekAttempt () throws Exception {
78+ RetrySettings retrySettings =
79+ FAST_RETRY_SETTINGS
80+ .toBuilder ()
81+ .setTotalTimeoutDuration (java .time .Duration .ofMillis (1000L ))
82+ .setMaxAttempts (100 )
83+ .build ();
8884 for (int executionsCount = 0 ; executionsCount < EXECUTIONS_COUNT ; executionsCount ++) {
89- final int maxRetries = 100 ;
9085
91- ScheduledExecutorService localExecutor = Executors .newSingleThreadScheduledExecutor ();
9286 FailingCallable callable = new FailingCallable (15 , "request" , "SUCCESS" , tracer );
9387
94- RetrySettings retrySettings =
95- FAST_RETRY_SETTINGS
96- .toBuilder ()
97- .setTotalTimeoutDuration (java .time .Duration .ofMillis (1000L ))
98- .setMaxAttempts (maxRetries )
99- .build ();
100-
10188 RetryingExecutorWithContext <String > executor =
102- getRetryingExecutor (getAlgorithm (retrySettings , 0 , null ), localExecutor );
89+ getRetryingExecutor (getAlgorithm (retrySettings , 0 , null ), scheduledExecutorService );
10390 RetryingFuture <String > future =
104- executor .createFuture (callable , FakeCallContext .createDefault ().withTracer (tracer ));
91+ executor .createFuture (
92+ callable ,
93+ FakeCallContext .createDefault ().withTracer (tracer ).withRetrySettings (retrySettings ));
10594 callable .setExternalFuture (future );
10695
10796 assertNull (future .peekAttemptResult ());
@@ -131,28 +120,28 @@ void testSuccessWithFailuresPeekAttempt() throws Exception {
131120 assertFutureSuccess (future );
132121 assertEquals (15 , future .getAttemptSettings ().getAttemptCount ());
133122 assertTrue (failedAttempts > 0 );
134- localExecutor .shutdownNow ();
135123 }
136124 }
137125
138126 @ Test
139127 void testSuccessWithFailuresGetAttempt () throws Exception {
128+ int maxRetries = 100 ;
129+ RetrySettings retrySettings =
130+ FAST_RETRY_SETTINGS
131+ .toBuilder ()
132+ .setTotalTimeoutDuration (java .time .Duration .ofMillis (1000L ))
133+ .setMaxAttempts (maxRetries )
134+ .build ();
140135 for (int executionsCount = 0 ; executionsCount < EXECUTIONS_COUNT ; executionsCount ++) {
141- final int maxRetries = 100 ;
142136
143- ScheduledExecutorService localExecutor = Executors .newSingleThreadScheduledExecutor ();
144137 FailingCallable callable = new FailingCallable (15 , "request" , "SUCCESS" , tracer );
145- RetrySettings retrySettings =
146- FAST_RETRY_SETTINGS
147- .toBuilder ()
148- .setTotalTimeoutDuration (java .time .Duration .ofMillis (1000L ))
149- .setMaxAttempts (maxRetries )
150- .build ();
151138
152139 RetryingExecutorWithContext <String > executor =
153- getRetryingExecutor (getAlgorithm (retrySettings , 0 , null ), localExecutor );
140+ getRetryingExecutor (getAlgorithm (retrySettings , 0 , null ), scheduledExecutorService );
154141 RetryingFuture <String > future =
155- executor .createFuture (callable , FakeCallContext .createDefault ().withTracer (tracer ));
142+ executor .createFuture (
143+ callable ,
144+ FakeCallContext .createDefault ().withTracer (tracer ).withRetrySettings (retrySettings ));
156145 callable .setExternalFuture (future );
157146
158147 assertNull (future .peekAttemptResult ());
@@ -185,75 +174,64 @@ void testSuccessWithFailuresGetAttempt() throws Exception {
185174 assertFutureSuccess (future );
186175 assertEquals (15 , future .getAttemptSettings ().getAttemptCount ());
187176 assertTrue (checks > 1 && checks <= maxRetries , "checks is equal to " + checks );
188- localExecutor .shutdownNow ();
189177 }
190178 }
191179
192- @ ParameterizedTest
193- @ MethodSource ("data" )
194- void testCancelGetAttempt (boolean withCustomRetrySettings ) throws Exception {
195- setUp (withCustomRetrySettings );
196- for (int executionsCount = 0 ; executionsCount < EXECUTIONS_COUNT ; executionsCount ++) {
197- ScheduledExecutorService localExecutor = Executors .newSingleThreadScheduledExecutor ();
198- final int maxRetries = 20 ;
199-
200- FailingCallable callable = new FailingCallable (maxRetries - 1 , "request" , "SUCCESS" , tracer );
201- RetrySettings retrySettings =
202- FAST_RETRY_SETTINGS
203- .toBuilder ()
204- .setTotalTimeoutDuration (java .time .Duration .ofMillis (5000L ))
205- .setMaxAttempts (maxRetries )
206- .build ();
207-
208- RetryingExecutorWithContext <String > executor =
209- getRetryingExecutor (getAlgorithm (retrySettings , 0 , null ), localExecutor );
210- RetryingFuture <String > future = executor .createFuture (callable , retryingContext );
211- callable .setExternalFuture (future );
212-
213- assertNull (future .peekAttemptResult ());
214- assertSame (future .getAttemptResult (), future .getAttemptResult ());
215- assertFalse (future .getAttemptResult ().isDone ());
216- assertFalse (future .getAttemptResult ().isCancelled ());
217-
218- future .setAttemptFuture (executor .submit (future ));
219-
220- CustomException exception ;
221- CancellationException cancellationException = null ;
222- int checks = 0 ;
223- int failedCancelations = 0 ;
224- do {
225- exception = null ;
226- checks ++;
227- Future <String > attemptResult = future .getAttemptResult ();
228- try {
229- attemptResult .get ();
230- assertNotNull (future .peekAttemptResult ());
231- } catch (CancellationException e ) {
232- cancellationException = e ;
233- } catch (ExecutionException e ) {
234- exception = (CustomException ) e .getCause ();
235- }
236- assertTrue (attemptResult .isDone ());
237- if (!future .cancel (true )) {
238- failedCancelations ++;
239- }
240- } while (exception != null && checks < maxRetries );
241-
242- assertTrue (future .isDone ());
243- assertNotNull (cancellationException );
244- // future.cancel(true) may return false sometimes, which is ok. Also, the every cancellation
245- // of
246- // an already cancelled future should return false (this is what -1 means here)
247- assertEquals (2 , checks - (failedCancelations - 1 ));
248- assertTrue (future .getAttemptSettings ().getAttemptCount () > 0 );
249- assertFutureCancel (future );
250- localExecutor .shutdownNow ();
251- }
180+ @ Test
181+ void testCancelGetAttempt () throws Exception {
182+ int maxRetries = 100 ;
183+ RetrySettings retrySettings =
184+ FAST_RETRY_SETTINGS
185+ .toBuilder ()
186+ .setInitialRpcTimeoutDuration (java .time .Duration .ofMillis (50L ))
187+ .setMaxRpcTimeoutDuration (java .time .Duration .ofMillis (50L ))
188+ .setTotalTimeoutDuration (java .time .Duration .ofMillis (5000L ))
189+ .setMaxAttempts (maxRetries )
190+ .build ();
191+ FailingCallable callable = new FailingCallable (maxRetries - 1 , "request" , "SUCCESS" , tracer );
192+
193+ RetryingExecutorWithContext <String > executor =
194+ getRetryingExecutor (getAlgorithm (retrySettings , 0 , null ), scheduledExecutorService );
195+ RetryingFuture <String > future =
196+ executor .createFuture (
197+ callable ,
198+ FakeCallContext .createDefault ().withTracer (tracer ).withRetrySettings (retrySettings ));
199+ callable .setExternalFuture (future );
200+
201+ assertNull (future .peekAttemptResult ());
202+ assertSame (future .getAttemptResult (), future .getAttemptResult ());
203+ assertFalse (future .getAttemptResult ().isDone ());
204+ assertFalse (future .getAttemptResult ().isCancelled ());
205+
206+ future .setAttemptFuture (executor .submit (future ));
207+
208+ CustomException exception ;
209+ CancellationException cancellationException = null ;
210+ int checks = 0 ;
211+ do {
212+ exception = null ;
213+ checks ++;
214+ Future <String > attemptResult = future .getAttemptResult ();
215+ try {
216+ attemptResult .get ();
217+ assertNotNull (future .peekAttemptResult ());
218+ } catch (CancellationException e ) {
219+ cancellationException = e ;
220+ } catch (ExecutionException e ) {
221+ exception = (CustomException ) e .getCause ();
222+ }
223+ future .cancel (true );
224+ assertTrue (attemptResult .isDone ());
225+ } while (exception != null && checks < maxRetries );
226+
227+ assertTrue (future .isDone ());
228+ assertNotNull (cancellationException );
229+ assertTrue (future .getAttemptSettings ().getAttemptCount () > 0 );
230+ assertFutureCancel (future );
252231 }
253232
254233 @ Test
255234 void testCancelOuterFutureAfterStart () throws Exception {
256- ScheduledExecutorService localExecutor = Executors .newSingleThreadScheduledExecutor ();
257235 RetrySettings retrySettings =
258236 FAST_RETRY_SETTINGS
259237 .toBuilder ()
@@ -278,9 +256,11 @@ void testCancelOuterFutureAfterStart() throws Exception {
278256 for (int executionsCount = 0 ; executionsCount < EXECUTIONS_COUNT ; executionsCount ++) {
279257 FailingCallable callable = new FailingCallable (4 , "request" , "SUCCESS" , tracer );
280258 RetryingExecutorWithContext <String > executor =
281- getRetryingExecutor (getAlgorithm (retrySettings , 0 , null ), localExecutor );
259+ getRetryingExecutor (getAlgorithm (retrySettings , 0 , null ), scheduledExecutorService );
282260 RetryingFuture <String > future =
283- executor .createFuture (callable , FakeCallContext .createDefault ().withTracer (tracer ));
261+ executor .createFuture (
262+ callable ,
263+ FakeCallContext .createDefault ().withTracer (tracer ).withRetrySettings (retrySettings ));
284264 callable .setExternalFuture (future );
285265 future .setAttemptFuture (executor .submit (future ));
286266
@@ -301,27 +281,29 @@ void testCancelOuterFutureAfterStart() throws Exception {
301281 assertTrue (future .getAttemptSettings ().getAttemptCount () > 0 );
302282 assertTrue (future .getAttemptSettings ().getAttemptCount () < 4 );
303283 }
304- localExecutor .shutdown ();
305- localExecutor .awaitTermination (10 , TimeUnit .SECONDS );
306284 }
307285
308286 @ Test
309287 void testCancelProxiedFutureAfterStart () throws Exception {
288+ RetrySettings retrySettings =
289+ FAST_RETRY_SETTINGS
290+ .toBuilder ()
291+ .setInitialRetryDelayDuration (java .time .Duration .ofMillis (1_000L ))
292+ .setMaxRetryDelayDuration (java .time .Duration .ofMillis (1_000L ))
293+ .setTotalTimeoutDuration (java .time .Duration .ofMillis (10_0000L ))
294+ .build ();
310295 // this is a heavy test, which takes a lot of time, so only few executions.
311296 for (int executionsCount = 0 ; executionsCount < 2 ; executionsCount ++) {
297+ // Use a test local executor for this test case due to the reasons listed below
312298 ScheduledExecutorService localExecutor = Executors .newSingleThreadScheduledExecutor ();
313299 FailingCallable callable = new FailingCallable (5 , "request" , "SUCCESS" , tracer );
314- RetrySettings retrySettings =
315- FAST_RETRY_SETTINGS
316- .toBuilder ()
317- .setInitialRetryDelayDuration (java .time .Duration .ofMillis (1_000L ))
318- .setMaxRetryDelayDuration (java .time .Duration .ofMillis (1_000L ))
319- .setTotalTimeoutDuration (java .time .Duration .ofMillis (10_0000L ))
320- .build ();
300+
321301 RetryingExecutorWithContext <String > executor =
322302 getRetryingExecutor (getAlgorithm (retrySettings , 0 , null ), localExecutor );
323303 RetryingFuture <String > future =
324- executor .createFuture (callable , FakeCallContext .createDefault ().withTracer (tracer ));
304+ executor .createFuture (
305+ callable ,
306+ FakeCallContext .createDefault ().withTracer (tracer ).withRetrySettings (retrySettings ));
325307 callable .setExternalFuture (future );
326308 future .setAttemptFuture (executor .submit (future ));
327309
@@ -330,8 +312,8 @@ void testCancelProxiedFutureAfterStart() throws Exception {
330312 // Note that shutdownNow() will not cancel internal FutureTasks automatically, which
331313 // may potentially cause another thread handing on RetryingFuture#get() call forever.
332314 // Canceling the tasks returned by shutdownNow() also does not help, because of missing
333- // feature
334- // in guava's ListenableScheduledFuture, which does not cancel itself, when its delegate is
315+ // feature in guava's ListenableScheduledFuture, which does not cancel itself, when its
316+ // delegate is
335317 // canceled.
336318 // So only the graceful shutdown() is supported properly.
337319 localExecutor .shutdown ();
0 commit comments