Skip to content

Commit 16a6bdd

Browse files
committed
Introduce java.time.Duration
1 parent daa04db commit 16a6bdd

File tree

2 files changed

+209
-0
lines changed

2 files changed

+209
-0
lines changed

src/main/java/org/springframework/retry/support/RetryTemplateBuilder.java

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.springframework.retry.support;
1717

18+
import java.time.Duration;
1819
import java.util.ArrayList;
1920
import java.util.List;
2021

@@ -83,6 +84,7 @@
8384
* @author Aleksandr Shamukov
8485
* @author Artem Bilan
8586
* @author Kim In Hoi
87+
* @author Andreas Ahlenstorf
8688
* @since 1.3
8789
*/
8890
public class RetryTemplateBuilder {
@@ -122,7 +124,9 @@ public RetryTemplateBuilder maxAttempts(int maxAttempts) {
122124
* @param timeout whole execution timeout in milliseconds
123125
* @return this
124126
* @see TimeoutRetryPolicy
127+
* @deprecated Use {@link #withTimeout(long)} instead.
125128
*/
129+
@Deprecated(since = "2.0.2", forRemoval = true)
126130
public RetryTemplateBuilder withinMillis(long timeout) {
127131
Assert.isTrue(timeout > 0, "Timeout should be positive");
128132
Assert.isNull(this.baseRetryPolicy, "You have already selected another retry policy");
@@ -132,6 +136,36 @@ public RetryTemplateBuilder withinMillis(long timeout) {
132136
return this;
133137
}
134138

139+
/**
140+
* Retry until {@code timeout} has passed since the initial attempt.
141+
* @param timeoutMillis timeout in milliseconds
142+
* @return this
143+
* @see TimeoutRetryPolicy
144+
* @throws IllegalArgumentException if timeout is {@literal <=} 0 or if another retry
145+
* policy has already been configured.
146+
* @since 2.0.2
147+
*/
148+
public RetryTemplateBuilder withTimeout(long timeoutMillis) {
149+
Assert.isTrue(timeoutMillis > 0, "timeoutMillis should be greater than 0");
150+
Assert.isNull(this.baseRetryPolicy, "You have already selected another retry policy");
151+
this.baseRetryPolicy = new TimeoutRetryPolicy(timeoutMillis);
152+
return this;
153+
}
154+
155+
/**
156+
* Retry until {@code timeout} has passed since the initial attempt.
157+
* @param timeout duration for how long retries should be attempted
158+
* @return this
159+
* @see TimeoutRetryPolicy
160+
* @throws IllegalArgumentException if timeout is {@code null} or 0, or if another
161+
* retry policy has already been configured.
162+
* @since 2.0.2
163+
*/
164+
public RetryTemplateBuilder withTimeout(Duration timeout) {
165+
Assert.notNull(timeout, "timeout is null");
166+
return this.withinMillis(timeout.toMillis());
167+
}
168+
135169
/**
136170
* Allows infinite retry, do not limit attempts by number or time.
137171
* <p>
@@ -180,6 +214,27 @@ public RetryTemplateBuilder exponentialBackoff(long initialInterval, double mult
180214
return exponentialBackoff(initialInterval, multiplier, maxInterval, false);
181215
}
182216

217+
/**
218+
* Use exponential backoff policy. The formula of backoff period:
219+
* <p>
220+
* {@code currentInterval = Math.min(initialInterval * Math.pow(multiplier, retryNum), maxInterval)}
221+
* <p>
222+
* (for first attempt retryNum = 0)
223+
* @param initialInterval initial sleep duration
224+
* @param multiplier backoff interval multiplier
225+
* @param maxInterval maximum backoff duration
226+
* @return this
227+
* @see ExponentialBackOffPolicy
228+
* @throws IllegalArgumentException if initialInterval is {@code null}, multiplier is
229+
* {@literal <=} 1, or if maxInterval is {@code null}
230+
* @since 2.0.2
231+
*/
232+
public RetryTemplateBuilder exponentialBackoff(Duration initialInterval, double multiplier, Duration maxInterval) {
233+
Assert.notNull(initialInterval, "initialInterval is null");
234+
Assert.notNull(maxInterval, "maxInterval is null");
235+
return exponentialBackoff(initialInterval.toMillis(), multiplier, maxInterval.toMillis(), false);
236+
}
237+
183238
/**
184239
* Use exponential backoff policy. The formula of backoff period (without randomness):
185240
* <p>
@@ -210,6 +265,31 @@ public RetryTemplateBuilder exponentialBackoff(long initialInterval, double mult
210265
return this;
211266
}
212267

268+
/**
269+
* Use exponential backoff policy. The formula of backoff period (without randomness):
270+
* <p>
271+
* {@code currentInterval = Math.min(initialInterval * Math.pow(multiplier, retryNum), maxInterval)}
272+
* <p>
273+
* (for first attempt retryNum = 0)
274+
* @param initialInterval initial sleep duration
275+
* @param multiplier backoff interval multiplier
276+
* @param maxInterval maximum backoff duration
277+
* @param withRandom adds some randomness to backoff intervals. For details, see
278+
* {@link ExponentialRandomBackOffPolicy}
279+
* @return this
280+
* @see ExponentialBackOffPolicy
281+
* @see ExponentialRandomBackOffPolicy
282+
* @throws IllegalArgumentException if initialInterval is {@code null}, multiplier is
283+
* {@literal <=} 1, or maxInterval is {@code null}
284+
* @since 2.0.2
285+
*/
286+
public RetryTemplateBuilder exponentialBackoff(Duration initialInterval, double multiplier, Duration maxInterval,
287+
boolean withRandom) {
288+
Assert.notNull(initialInterval, "initialInterval is null");
289+
Assert.notNull(maxInterval, "maxInterval is null");
290+
return this.exponentialBackoff(initialInterval.toMillis(), multiplier, maxInterval.toMillis(), withRandom);
291+
}
292+
213293
/**
214294
* Perform each retry after fixed amount of time.
215295
* @param interval fixed interval in milliseconds
@@ -225,6 +305,24 @@ public RetryTemplateBuilder fixedBackoff(long interval) {
225305
return this;
226306
}
227307

308+
/**
309+
* Perform each retry after fixed amount of time.
310+
* @param interval fixed backoff duration
311+
* @return this
312+
* @see FixedBackOffPolicy
313+
* @throws IllegalArgumentException if another backoff policy has already been
314+
* configured, interval is {@code null} or less than 1 millisecond
315+
* @since 2.0.2
316+
*/
317+
public RetryTemplateBuilder fixedBackoff(Duration interval) {
318+
Assert.notNull(interval, "interval is null");
319+
320+
long millis = interval.toMillis();
321+
Assert.isTrue(millis >= 1, "interval is less than 1 millisecond");
322+
323+
return this.fixedBackoff(millis);
324+
}
325+
228326
/**
229327
* Use {@link UniformRandomBackOffPolicy}, see it's doc for details.
230328
* @param minInterval in milliseconds
@@ -244,6 +342,23 @@ public RetryTemplateBuilder uniformRandomBackoff(long minInterval, long maxInter
244342
return this;
245343
}
246344

345+
/**
346+
* Use {@link UniformRandomBackOffPolicy}.
347+
* @param minInterval minimum backoff duration
348+
* @param maxInterval maximum backoff duration
349+
* @return this
350+
* @see UniformRandomBackOffPolicy
351+
* @throws IllegalArgumentException if minInterval is {@code null} or {@literal <} 1,
352+
* maxInterval is {@code null} or {@literal <} 1, maxInterval {@literal >=}
353+
* minInterval or if another backoff policy has already been configured.
354+
* @since 2.0.2
355+
*/
356+
public RetryTemplateBuilder uniformRandomBackoff(Duration minInterval, Duration maxInterval) {
357+
Assert.notNull(minInterval, "minInterval is null");
358+
Assert.notNull(maxInterval, "maxInterval is null");
359+
return this.uniformRandomBackoff(minInterval.toMillis(), maxInterval.toMillis());
360+
}
361+
247362
/**
248363
* Do not pause between attempts, retry immediately.
249364
* @return this

src/test/java/org/springframework/retry/support/RetryTemplateBuilderTests.java

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.io.FileNotFoundException;
2020
import java.io.IOException;
21+
import java.time.Duration;
2122
import java.util.Arrays;
2223
import java.util.Collections;
2324
import java.util.List;
@@ -29,6 +30,7 @@
2930
import org.springframework.retry.RetryPolicy;
3031
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
3132
import org.springframework.retry.backoff.ExponentialRandomBackOffPolicy;
33+
import org.springframework.retry.backoff.FixedBackOffPolicy;
3234
import org.springframework.retry.backoff.NoBackOffPolicy;
3335
import org.springframework.retry.backoff.UniformRandomBackOffPolicy;
3436
import org.springframework.retry.policy.AlwaysRetryPolicy;
@@ -53,6 +55,7 @@
5355
* @author Aleksandr Shamukov
5456
* @author Kim In Hoi
5557
* @author Gary Russell
58+
* @author Andreas Ahlenstorf
5659
*/
5760
public class RetryTemplateBuilderTests {
5861

@@ -111,12 +114,14 @@ public void testBasicCustomization() {
111114
/* ---------------- Retry policy -------------- */
112115

113116
@Test
117+
@SuppressWarnings("removal")
114118
public void testFailOnRetryPoliciesConflict() {
115119
assertThatIllegalArgumentException()
116120
.isThrownBy(() -> RetryTemplate.builder().maxAttempts(3).withinMillis(1000).build());
117121
}
118122

119123
@Test
124+
@SuppressWarnings("removal")
120125
public void testTimeoutPolicy() {
121126
RetryTemplate template = RetryTemplate.builder().withinMillis(10000).build();
122127

@@ -127,6 +132,28 @@ public void testTimeoutPolicy() {
127132
assertThat(((TimeoutRetryPolicy) policyTuple.baseRetryPolicy).getTimeout()).isEqualTo(10000);
128133
}
129134

135+
@Test
136+
public void testTimeoutMillis() {
137+
RetryTemplate template = RetryTemplate.builder().withTimeout(10000).build();
138+
139+
PolicyTuple policyTuple = PolicyTuple.extractWithAsserts(template);
140+
assertDefaultClassifier(policyTuple);
141+
142+
assertThat(policyTuple.baseRetryPolicy).isInstanceOf(TimeoutRetryPolicy.class);
143+
assertThat(((TimeoutRetryPolicy) policyTuple.baseRetryPolicy).getTimeout()).isEqualTo(10000);
144+
}
145+
146+
@Test
147+
public void testTimeoutDuration() {
148+
RetryTemplate template = RetryTemplate.builder().withTimeout(Duration.ofSeconds(3)).build();
149+
150+
PolicyTuple policyTuple = PolicyTuple.extractWithAsserts(template);
151+
assertDefaultClassifier(policyTuple);
152+
153+
assertThat(policyTuple.baseRetryPolicy).isInstanceOf(TimeoutRetryPolicy.class);
154+
assertThat(((TimeoutRetryPolicy) policyTuple.baseRetryPolicy).getTimeout()).isEqualTo(3000);
155+
}
156+
130157
@Test
131158
public void testInfiniteRetry() {
132159
RetryTemplate template = RetryTemplate.builder().infiniteRetry().build();
@@ -190,24 +217,91 @@ public void testFailOnBackOffPolicyConflict() {
190217
.isThrownBy(() -> RetryTemplate.builder().noBackoff().fixedBackoff(1000).build());
191218
}
192219

220+
@Test
221+
public void testFixedBackoff() {
222+
RetryTemplate template = RetryTemplate.builder().fixedBackoff(200).build();
223+
FixedBackOffPolicy policy = getPropertyValue(template, "backOffPolicy", FixedBackOffPolicy.class);
224+
225+
assertThat(policy.getBackOffPeriod()).isEqualTo(200);
226+
}
227+
228+
@Test
229+
public void testFixedBackoffDuration() {
230+
RetryTemplate template = RetryTemplate.builder().fixedBackoff(Duration.ofSeconds(1)).build();
231+
FixedBackOffPolicy policy = getPropertyValue(template, "backOffPolicy", FixedBackOffPolicy.class);
232+
233+
assertThat(policy.getBackOffPeriod()).isEqualTo(1000);
234+
}
235+
193236
@Test
194237
public void testUniformRandomBackOff() {
195238
RetryTemplate template = RetryTemplate.builder().uniformRandomBackoff(10, 100).build();
196239
assertThat(getPropertyValue(template, "backOffPolicy")).isInstanceOf(UniformRandomBackOffPolicy.class);
197240
}
198241

242+
@Test
243+
public void testUniformRandomBackOffDuration() {
244+
RetryTemplate template = RetryTemplate.builder()
245+
.uniformRandomBackoff(Duration.ofSeconds(1), Duration.ofSeconds(2))
246+
.build();
247+
248+
UniformRandomBackOffPolicy policy = getPropertyValue(template, "backOffPolicy",
249+
UniformRandomBackOffPolicy.class);
250+
251+
assertThat(policy.getMinBackOffPeriod()).isEqualTo(1000);
252+
assertThat(policy.getMaxBackOffPeriod()).isEqualTo(2000);
253+
}
254+
199255
@Test
200256
public void testNoBackOff() {
201257
RetryTemplate template = RetryTemplate.builder().noBackoff().build();
202258
assertThat(getPropertyValue(template, "backOffPolicy")).isInstanceOf(NoBackOffPolicy.class);
203259
}
204260

261+
@Test
262+
public void testExponentialBackoff() {
263+
RetryTemplate template = RetryTemplate.builder().exponentialBackoff(10, 2, 500).build();
264+
ExponentialBackOffPolicy policy = getPropertyValue(template, "backOffPolicy", ExponentialBackOffPolicy.class);
265+
266+
assertThat(policy.getInitialInterval()).isEqualTo(10);
267+
assertThat(policy.getMultiplier()).isEqualTo(2);
268+
assertThat(policy.getMaxInterval()).isEqualTo(500);
269+
}
270+
271+
@Test
272+
public void testExponentialBackoffDuration() {
273+
RetryTemplate template = RetryTemplate.builder()
274+
.exponentialBackoff(Duration.ofSeconds(2), 2, Duration.ofSeconds(3))
275+
.build();
276+
277+
ExponentialBackOffPolicy policy = getPropertyValue(template, "backOffPolicy", ExponentialBackOffPolicy.class);
278+
279+
assertThat(policy.getInitialInterval()).isEqualTo(2000);
280+
assertThat(policy.getMultiplier()).isEqualTo(2);
281+
assertThat(policy.getMaxInterval()).isEqualTo(3000);
282+
assertThat(policy.getMaxInterval()).isEqualTo(3000);
283+
}
284+
205285
@Test
206286
public void testExpBackOffWithRandom() {
207287
RetryTemplate template = RetryTemplate.builder().exponentialBackoff(10, 2, 500, true).build();
208288
assertThat(getPropertyValue(template, "backOffPolicy")).isInstanceOf(ExponentialRandomBackOffPolicy.class);
209289
}
210290

291+
@Test
292+
public void testExponentialRandomBackoffDuration() {
293+
RetryTemplate template = RetryTemplate.builder()
294+
.exponentialBackoff(Duration.ofSeconds(2), 2, Duration.ofSeconds(3), true)
295+
.build();
296+
297+
ExponentialRandomBackOffPolicy policy = getPropertyValue(template, "backOffPolicy",
298+
ExponentialRandomBackOffPolicy.class);
299+
300+
assertThat(policy.getInitialInterval()).isEqualTo(2000);
301+
assertThat(policy.getMultiplier()).isEqualTo(2);
302+
assertThat(policy.getMaxInterval()).isEqualTo(3000);
303+
}
304+
211305
@Test
212306
public void testValidateInitAndMax() {
213307
assertThatIllegalArgumentException()

0 commit comments

Comments
 (0)