17
17
package org .springframework .core .retry ;
18
18
19
19
import java .time .Duration ;
20
+ import java .util .concurrent .atomic .AtomicInteger ;
20
21
22
+ import org .junit .jupiter .api .BeforeEach ;
21
23
import org .junit .jupiter .api .Test ;
22
24
23
25
import org .springframework .util .backoff .FixedBackOff ;
@@ -36,95 +38,99 @@ class RetryTemplateTests {
36
38
37
39
private final RetryTemplate retryTemplate = new RetryTemplate ();
38
40
39
- @ Test
40
- void retryWithSuccess () throws Exception {
41
- Retryable <String > retryable = new Retryable <>() {
42
41
43
- int failure ;
42
+ @ BeforeEach
43
+ void configureTemplate () {
44
+ this .retryTemplate .setBackOffPolicy (new FixedBackOff (Duration .ofMillis (10 )));
45
+ }
44
46
45
- @ Override
46
- public String execute () throws Exception {
47
- if ( failure ++ < 2 ) {
48
- throw new Exception ( "Error while invoking greeting service" );
49
- }
50
- return "hello world " ;
51
- }
47
+ @ Test
48
+ void retryWithImmediateSuccess () throws Exception {
49
+ AtomicInteger invocationCount = new AtomicInteger ();
50
+ Retryable < String > retryable = () -> {
51
+ invocationCount . incrementAndGet ();
52
+ return "always succeeds " ;
53
+ };
52
54
53
- @ Override
54
- public String getName () {
55
- return "greeting service" ;
55
+ assertThat (invocationCount ).hasValue (0 );
56
+ assertThat (retryTemplate .execute (retryable )).isEqualTo ("always succeeds" );
57
+ assertThat (invocationCount ).hasValue (1 );
58
+ }
59
+
60
+ @ Test
61
+ void retryWithSuccessAfterInitialFailures () throws Exception {
62
+ AtomicInteger invocationCount = new AtomicInteger ();
63
+ Retryable <String > retryable = () -> {
64
+ if (invocationCount .incrementAndGet () <= 2 ) {
65
+ throw new Exception ("Boom!" );
56
66
}
67
+ return "finally succeeded" ;
57
68
};
58
69
59
- retryTemplate . setBackOffPolicy ( new FixedBackOff ( Duration . ofMillis ( 10 )) );
60
-
61
- assertThat (retryTemplate . execute ( retryable )). isEqualTo ( "hello world" );
70
+ assertThat ( invocationCount ). hasValue ( 0 );
71
+ assertThat ( retryTemplate . execute ( retryable )). isEqualTo ( "finally succeeded" );
72
+ assertThat (invocationCount ). hasValue ( 3 );
62
73
}
63
74
64
75
@ Test
65
- void retryWithFailure () {
66
- Exception exception = new Exception ("Error while invoking greeting service" );
76
+ void retryWithExhaustedPolicy () {
77
+ AtomicInteger invocationCount = new AtomicInteger ();
78
+ RuntimeException exception = new RuntimeException ("Boom!" );
67
79
68
80
Retryable <String > retryable = new Retryable <>() {
69
81
@ Override
70
- public String execute () throws Exception {
82
+ public String execute () {
83
+ invocationCount .incrementAndGet ();
71
84
throw exception ;
72
85
}
73
86
74
87
@ Override
75
88
public String getName () {
76
- return "greeting service " ;
89
+ return "test " ;
77
90
}
78
91
};
79
92
80
- retryTemplate .setBackOffPolicy (new FixedBackOff (Duration .ofMillis (10 )));
81
-
93
+ assertThat (invocationCount ).hasValue (0 );
82
94
assertThatExceptionOfType (RetryException .class )
83
95
.isThrownBy (() -> retryTemplate .execute (retryable ))
84
- .withMessage ("Retry policy for operation 'greeting service ' exhausted; aborting execution" )
96
+ .withMessage ("Retry policy for operation 'test ' exhausted; aborting execution" )
85
97
.withCause (exception );
98
+ // 4 = 1 initial invocation + 3 retry attempts
99
+ assertThat (invocationCount ).hasValue (4 );
86
100
}
87
101
88
102
@ Test
89
- void retrySpecificException () {
90
-
91
- @ SuppressWarnings ("serial" )
92
- class TechnicalException extends Exception {
93
- public TechnicalException (String message ) {
94
- super (message );
95
- }
96
- }
97
-
98
- TechnicalException technicalException = new TechnicalException ("Error while invoking greeting service" );
103
+ void retryWithFailingRetryableAndCustomRetryPolicy () {
104
+ AtomicInteger invocationCount = new AtomicInteger ();
105
+ RuntimeException exception = new NumberFormatException ();
99
106
100
107
Retryable <String > retryable = new Retryable <>() {
101
108
@ Override
102
- public String execute () throws TechnicalException {
103
- throw technicalException ;
109
+ public String execute () {
110
+ invocationCount .incrementAndGet ();
111
+ throw exception ;
104
112
}
105
113
106
114
@ Override
107
115
public String getName () {
108
- return "greeting service" ;
109
- }
110
- };
111
-
112
- RetryPolicy retryPolicy = () -> new RetryExecution () {
113
- int retryAttempts ;
114
-
115
- @ Override
116
- public boolean shouldRetry (Throwable throwable ) {
117
- return (this .retryAttempts ++ < 3 && throwable instanceof TechnicalException );
116
+ return "always fails" ;
118
117
}
119
118
};
120
119
120
+ AtomicInteger retryCount = new AtomicInteger ();
121
+ // Custom RetryPolicy that only retries for a NumberFormatException and max 5 retry attempts.
122
+ RetryPolicy retryPolicy = () -> throwable -> (retryCount .incrementAndGet () <= 5 && throwable instanceof NumberFormatException );
121
123
retryTemplate .setRetryPolicy (retryPolicy );
122
- retryTemplate .setBackOffPolicy (new FixedBackOff (Duration .ofMillis (10 )));
123
124
125
+ assertThat (invocationCount ).hasValue (0 );
126
+ assertThat (retryCount ).hasValue (0 );
124
127
assertThatExceptionOfType (RetryException .class )
125
128
.isThrownBy (() -> retryTemplate .execute (retryable ))
126
- .withMessage ("Retry policy for operation 'greeting service' exhausted; aborting execution" )
127
- .withCause (technicalException );
129
+ .withMessage ("Retry policy for operation 'always fails' exhausted; aborting execution" )
130
+ .withCause (exception );
131
+ // 6 = 1 initial invocation + 5 retry attempts
132
+ assertThat (invocationCount ).hasValue (6 );
133
+ assertThat (retryCount ).hasValue (6 );
128
134
}
129
135
130
136
}
0 commit comments