0
# Retry Strategies
1
2
Comprehensive retry mechanisms with configurable delays, maximum attempts, and conditional retry logic. Supports standard retry patterns, custom backoff strategies, and predicate-based conditional retries.
3
4
## Capabilities
5
6
### Basic Retry
7
8
Standard retry functionality with configurable maximum attempts, delays, and exception handling.
9
10
```java { .api }
11
@Retry(
12
maxRetries = 3,
13
delay = 1000,
14
delayUnit = ChronoUnit.MILLISECONDS,
15
maxDuration = 30000,
16
durationUnit = ChronoUnit.MILLISECONDS,
17
jitter = 200,
18
jitterDelayUnit = ChronoUnit.MILLISECONDS,
19
retryOn = {IOException.class, TimeoutException.class},
20
abortOn = {SecurityException.class}
21
)
22
public ReturnType retryableMethod() throws Exception;
23
```
24
25
#### Parameters
26
27
- `maxRetries` - Maximum number of retry attempts (default: 3)
28
- `delay` - Delay between retry attempts in specified units (default: 0)
29
- `delayUnit` - Time unit for delay (default: MILLIS)
30
- `maxDuration` - Maximum total time to spend retrying (default: 180000ms)
31
- `durationUnit` - Time unit for max duration (default: MILLIS)
32
- `jitter` - Random jitter added to delays (default: 200ms)
33
- `jitterDelayUnit` - Time unit for jitter (default: MILLIS)
34
- `retryOn` - Exception types that trigger retry (default: Exception.class)
35
- `abortOn` - Exception types that prevent retry (takes precedence over retryOn)
36
37
#### Usage Example
38
39
```java
40
@ApplicationScoped
41
public class ExternalApiService {
42
43
// Basic retry with exponential backoff
44
@Retry(maxRetries = 5, delay = 1000)
45
@ExponentialBackoff(factor = 2, maxDelay = 30000)
46
public String callExternalApi(String endpoint) throws IOException {
47
// Implementation that may fail and should be retried
48
return httpClient.get(endpoint);
49
}
50
51
// Retry with specific exceptions
52
@Retry(
53
maxRetries = 3,
54
retryOn = {SocketTimeoutException.class, ConnectException.class},
55
abortOn = {SecurityException.class, IllegalArgumentException.class}
56
)
57
public ApiResponse secureApiCall(String token, String data) {
58
return authenticatedHttpClient.post(data, token);
59
}
60
}
61
```
62
63
### Conditional Retry
64
65
Advanced retry logic based on exception types, return values, or custom predicates.
66
67
```java { .api }
68
@RetryWhen(
69
exception = ExceptionPredicate.class,
70
result = ResultPredicate.class
71
)
72
public ReturnType conditionalRetryMethod();
73
74
// Predicate interfaces
75
class ExceptionPredicate implements Predicate<Throwable> {
76
public boolean test(Throwable throwable);
77
}
78
79
class ResultPredicate implements Predicate<Object> {
80
public boolean test(Object result);
81
}
82
```
83
84
#### Usage Example
85
86
```java
87
@ApplicationScoped
88
public class DataService {
89
90
// Retry based on custom exception logic
91
@RetryWhen(exception = RetryableHttpExceptionPredicate.class)
92
public ApiData fetchData(String id) {
93
return apiClient.getData(id);
94
}
95
96
// Retry based on return value
97
@RetryWhen(result = IncompleteDataPredicate.class)
98
public DataSet processData(String input) {
99
return dataProcessor.process(input);
100
}
101
}
102
103
// Custom predicates
104
public class RetryableHttpExceptionPredicate implements Predicate<Throwable> {
105
@Override
106
public boolean test(Throwable throwable) {
107
if (throwable instanceof HttpException) {
108
HttpException httpEx = (HttpException) throwable;
109
// Retry on 5xx server errors but not 4xx client errors
110
return httpEx.getStatusCode() >= 500;
111
}
112
return false;
113
}
114
}
115
116
public class IncompleteDataPredicate implements Predicate<Object> {
117
@Override
118
public boolean test(Object result) {
119
if (result instanceof DataSet) {
120
DataSet dataSet = (DataSet) result;
121
// Retry if data set is incomplete
122
return dataSet.isEmpty() || !dataSet.isComplete();
123
}
124
return false;
125
}
126
}
127
```
128
129
### Exponential Backoff
130
131
Exponential delay growth between retry attempts to reduce load on failing systems.
132
133
```java { .api }
134
@ExponentialBackoff(
135
factor = 2,
136
maxDelay = 60000,
137
maxDelayUnit = ChronoUnit.MILLISECONDS
138
)
139
public ReturnType exponentialBackoffMethod();
140
```
141
142
#### Parameters
143
144
- `factor` - Multiplicative factor for delay growth (default: 2)
145
- `maxDelay` - Maximum delay between retries (default: 1 minute)
146
- `maxDelayUnit` - Time unit for max delay (default: MILLIS)
147
148
#### Usage Example
149
150
```java
151
@ApplicationScoped
152
public class DatabaseService {
153
154
// Database retry with exponential backoff
155
@Retry(maxRetries = 5, delay = 500)
156
@ExponentialBackoff(factor = 3, maxDelay = 30000)
157
public QueryResult executeQuery(String sql) throws SQLException {
158
return database.query(sql);
159
}
160
161
// Combined with circuit breaker for resilience
162
@Retry(maxRetries = 3)
163
@ExponentialBackoff()
164
@CircuitBreaker(requestVolumeThreshold = 10)
165
public void performDatabaseUpdate(UpdateQuery query) throws SQLException {
166
database.execute(query);
167
}
168
}
169
```
170
171
### Fibonacci Backoff
172
173
Fibonacci sequence-based delays for more gradual backoff than exponential.
174
175
```java { .api }
176
@FibonacciBackoff(
177
maxDelay = 60000,
178
maxDelayUnit = ChronoUnit.MILLISECONDS
179
)
180
public ReturnType fibonacciBackoffMethod();
181
```
182
183
#### Parameters
184
185
- `maxDelay` - Maximum delay between retries (default: 1 minute)
186
- `maxDelayUnit` - Time unit for max delay (default: MILLIS)
187
188
#### Usage Example
189
190
```java
191
@ApplicationScoped
192
public class MessageService {
193
194
// Message queue retry with Fibonacci backoff
195
@Retry(maxRetries = 8, delay = 100)
196
@FibonacciBackoff(maxDelay = 20000)
197
public void sendMessage(Message message) throws MessagingException {
198
messageQueue.send(message);
199
}
200
}
201
```
202
203
### Custom Backoff
204
205
Custom backoff strategies for specialized retry delay patterns.
206
207
```java { .api }
208
@CustomBackoff(CustomBackoffStrategy.class)
209
public ReturnType customBackoffMethod();
210
211
// Custom backoff strategy interface
212
interface CustomBackoffStrategy {
213
long nextDelayInMillis(int attemptIndex);
214
}
215
```
216
217
#### Usage Example
218
219
```java
220
@ApplicationScoped
221
public class SpecializedService {
222
223
// Custom backoff for API rate limiting
224
@Retry(maxRetries = 10)
225
@CustomBackoff(RateLimitBackoffStrategy.class)
226
public ApiResponse callRateLimitedApi(String endpoint) {
227
return apiClient.get(endpoint);
228
}
229
}
230
231
// Custom backoff implementation
232
public class RateLimitBackoffStrategy implements CustomBackoffStrategy {
233
private static final long[] DELAYS = {1000, 2000, 5000, 10000, 20000};
234
235
@Override
236
public long nextDelayInMillis(int attemptIndex) {
237
if (attemptIndex < DELAYS.length) {
238
return DELAYS[attemptIndex];
239
}
240
// For attempts beyond defined delays, use maximum delay
241
return DELAYS[DELAYS.length - 1];
242
}
243
}
244
```
245
246
### Before Retry Hooks
247
248
Execute custom logic before each retry attempt for logging, cleanup, or state management.
249
250
```java { .api }
251
@BeforeRetry(BeforeRetryHandler.class)
252
public ReturnType beforeRetryMethod();
253
254
// Handler interface
255
interface BeforeRetryHandler {
256
void handle(InvocationContext context);
257
}
258
259
// Alternative: method-based before retry (build-time configuration)
260
@BeforeRetry(methodName = "handleBeforeRetry")
261
public ReturnType methodBasedBeforeRetry();
262
263
public void handleBeforeRetry() {
264
// Custom before retry logic
265
}
266
```
267
268
#### Usage Example
269
270
```java
271
@ApplicationScoped
272
public class MonitoredService {
273
274
@Inject
275
Logger logger;
276
277
@Inject
278
MetricsCollector metrics;
279
280
// Before retry with custom handler
281
@Retry(maxRetries = 3)
282
@BeforeRetry(RetryLoggingHandler.class)
283
public String monitoredApiCall(String endpoint) throws Exception {
284
return externalApi.call(endpoint);
285
}
286
287
// Before retry with method
288
@Retry(maxRetries = 5)
289
@BeforeRetry(methodName = "logRetryAttempt")
290
public void importantOperation() throws Exception {
291
performCriticalTask();
292
}
293
294
public void logRetryAttempt() {
295
logger.warn("Retrying important operation due to failure");
296
metrics.incrementRetryCounter("important-operation");
297
}
298
}
299
300
// Custom before retry handler
301
public class RetryLoggingHandler implements BeforeRetryHandler {
302
@Inject
303
Logger logger;
304
305
@Override
306
public void handle(InvocationContext context) {
307
String methodName = context.getMethod().getName();
308
Throwable failure = context.getFailure();
309
logger.info("Retrying method {} due to {}", methodName, failure.getClass().getSimpleName());
310
}
311
}
312
```
313
314
## Types
315
316
### Core Retry Types
317
318
```java { .api }
319
// Time units for delays and durations
320
enum ChronoUnit {
321
NANOS, MICROS, MILLIS, SECONDS, MINUTES, HOURS, HALF_DAYS, DAYS
322
}
323
324
// Invocation context for before retry handlers
325
interface InvocationContext {
326
Method getMethod();
327
Object[] getParameters();
328
Object getTarget();
329
Throwable getFailure();
330
Map<String, Object> getContextData();
331
}
332
333
// Predicate for conditional retry
334
interface Predicate<T> {
335
boolean test(T t);
336
}
337
```
338
339
### Strategy Implementation Types
340
341
```java { .api }
342
// Custom backoff strategy interface
343
interface CustomBackoffStrategy {
344
/**
345
* Calculate the next delay based on attempt index
346
* @param attemptIndex Zero-based index of the retry attempt
347
* @return Delay in milliseconds before next retry
348
*/
349
long nextDelayInMillis(int attemptIndex);
350
}
351
352
// Before retry handler interface
353
interface BeforeRetryHandler {
354
/**
355
* Handle logic to execute before each retry attempt
356
* @param context Invocation context with method and failure information
357
*/
358
void handle(InvocationContext context);
359
}
360
```