CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-quarkus--quarkus-smallrye-fault-tolerance

Build fault-tolerant network services

Pending
Overview
Eval results
Files

retry-strategies.mddocs/

Retry Strategies

Comprehensive retry mechanisms with configurable delays, maximum attempts, and conditional retry logic. Supports standard retry patterns, custom backoff strategies, and predicate-based conditional retries.

Capabilities

Basic Retry

Standard retry functionality with configurable maximum attempts, delays, and exception handling.

@Retry(
    maxRetries = 3,
    delay = 1000,
    delayUnit = ChronoUnit.MILLISECONDS,
    maxDuration = 30000,
    durationUnit = ChronoUnit.MILLISECONDS,
    jitter = 200,
    jitterDelayUnit = ChronoUnit.MILLISECONDS,
    retryOn = {IOException.class, TimeoutException.class},
    abortOn = {SecurityException.class}
)
public ReturnType retryableMethod() throws Exception;

Parameters

  • maxRetries - Maximum number of retry attempts (default: 3)
  • delay - Delay between retry attempts in specified units (default: 0)
  • delayUnit - Time unit for delay (default: MILLIS)
  • maxDuration - Maximum total time to spend retrying (default: 180000ms)
  • durationUnit - Time unit for max duration (default: MILLIS)
  • jitter - Random jitter added to delays (default: 200ms)
  • jitterDelayUnit - Time unit for jitter (default: MILLIS)
  • retryOn - Exception types that trigger retry (default: Exception.class)
  • abortOn - Exception types that prevent retry (takes precedence over retryOn)

Usage Example

@ApplicationScoped
public class ExternalApiService {
    
    // Basic retry with exponential backoff
    @Retry(maxRetries = 5, delay = 1000)
    @ExponentialBackoff(factor = 2, maxDelay = 30000)
    public String callExternalApi(String endpoint) throws IOException {
        // Implementation that may fail and should be retried
        return httpClient.get(endpoint);
    }
    
    // Retry with specific exceptions
    @Retry(
        maxRetries = 3,
        retryOn = {SocketTimeoutException.class, ConnectException.class},
        abortOn = {SecurityException.class, IllegalArgumentException.class}
    )
    public ApiResponse secureApiCall(String token, String data) {
        return authenticatedHttpClient.post(data, token);
    }
}

Conditional Retry

Advanced retry logic based on exception types, return values, or custom predicates.

@RetryWhen(
    exception = ExceptionPredicate.class,
    result = ResultPredicate.class
)
public ReturnType conditionalRetryMethod();

// Predicate interfaces
class ExceptionPredicate implements Predicate<Throwable> {
    public boolean test(Throwable throwable);
}

class ResultPredicate implements Predicate<Object> {
    public boolean test(Object result);
}

Usage Example

@ApplicationScoped
public class DataService {
    
    // Retry based on custom exception logic
    @RetryWhen(exception = RetryableHttpExceptionPredicate.class)
    public ApiData fetchData(String id) {
        return apiClient.getData(id);
    }
    
    // Retry based on return value
    @RetryWhen(result = IncompleteDataPredicate.class)
    public DataSet processData(String input) {
        return dataProcessor.process(input);
    }
}

// Custom predicates
public class RetryableHttpExceptionPredicate implements Predicate<Throwable> {
    @Override
    public boolean test(Throwable throwable) {
        if (throwable instanceof HttpException) {
            HttpException httpEx = (HttpException) throwable;
            // Retry on 5xx server errors but not 4xx client errors
            return httpEx.getStatusCode() >= 500;
        }
        return false;
    }
}

public class IncompleteDataPredicate implements Predicate<Object> {
    @Override
    public boolean test(Object result) {
        if (result instanceof DataSet) {
            DataSet dataSet = (DataSet) result;
            // Retry if data set is incomplete
            return dataSet.isEmpty() || !dataSet.isComplete();
        }
        return false;
    }
}

Exponential Backoff

Exponential delay growth between retry attempts to reduce load on failing systems.

@ExponentialBackoff(
    factor = 2,
    maxDelay = 60000,
    maxDelayUnit = ChronoUnit.MILLISECONDS
)
public ReturnType exponentialBackoffMethod();

Parameters

  • factor - Multiplicative factor for delay growth (default: 2)
  • maxDelay - Maximum delay between retries (default: 1 minute)
  • maxDelayUnit - Time unit for max delay (default: MILLIS)

Usage Example

@ApplicationScoped
public class DatabaseService {
    
    // Database retry with exponential backoff
    @Retry(maxRetries = 5, delay = 500)
    @ExponentialBackoff(factor = 3, maxDelay = 30000)
    public QueryResult executeQuery(String sql) throws SQLException {
        return database.query(sql);
    }
    
    // Combined with circuit breaker for resilience
    @Retry(maxRetries = 3)
    @ExponentialBackoff()
    @CircuitBreaker(requestVolumeThreshold = 10)
    public void performDatabaseUpdate(UpdateQuery query) throws SQLException {
        database.execute(query);
    }
}

Fibonacci Backoff

Fibonacci sequence-based delays for more gradual backoff than exponential.

@FibonacciBackoff(
    maxDelay = 60000,
    maxDelayUnit = ChronoUnit.MILLISECONDS
)
public ReturnType fibonacciBackoffMethod();

Parameters

  • maxDelay - Maximum delay between retries (default: 1 minute)
  • maxDelayUnit - Time unit for max delay (default: MILLIS)

Usage Example

@ApplicationScoped
public class MessageService {
    
    // Message queue retry with Fibonacci backoff
    @Retry(maxRetries = 8, delay = 100)
    @FibonacciBackoff(maxDelay = 20000)
    public void sendMessage(Message message) throws MessagingException {
        messageQueue.send(message);
    }
}

Custom Backoff

Custom backoff strategies for specialized retry delay patterns.

@CustomBackoff(CustomBackoffStrategy.class)
public ReturnType customBackoffMethod();

// Custom backoff strategy interface
interface CustomBackoffStrategy {
    long nextDelayInMillis(int attemptIndex);
}

Usage Example

@ApplicationScoped
public class SpecializedService {
    
    // Custom backoff for API rate limiting
    @Retry(maxRetries = 10)
    @CustomBackoff(RateLimitBackoffStrategy.class)
    public ApiResponse callRateLimitedApi(String endpoint) {
        return apiClient.get(endpoint);
    }
}

// Custom backoff implementation
public class RateLimitBackoffStrategy implements CustomBackoffStrategy {
    private static final long[] DELAYS = {1000, 2000, 5000, 10000, 20000};
    
    @Override
    public long nextDelayInMillis(int attemptIndex) {
        if (attemptIndex < DELAYS.length) {
            return DELAYS[attemptIndex];
        }
        // For attempts beyond defined delays, use maximum delay
        return DELAYS[DELAYS.length - 1];
    }
}

Before Retry Hooks

Execute custom logic before each retry attempt for logging, cleanup, or state management.

@BeforeRetry(BeforeRetryHandler.class)
public ReturnType beforeRetryMethod();

// Handler interface
interface BeforeRetryHandler {
    void handle(InvocationContext context);
}

// Alternative: method-based before retry (build-time configuration)
@BeforeRetry(methodName = "handleBeforeRetry")
public ReturnType methodBasedBeforeRetry();

public void handleBeforeRetry() {
    // Custom before retry logic
}

Usage Example

@ApplicationScoped
public class MonitoredService {
    
    @Inject
    Logger logger;
    
    @Inject
    MetricsCollector metrics;
    
    // Before retry with custom handler
    @Retry(maxRetries = 3)
    @BeforeRetry(RetryLoggingHandler.class)
    public String monitoredApiCall(String endpoint) throws Exception {
        return externalApi.call(endpoint);
    }
    
    // Before retry with method
    @Retry(maxRetries = 5)
    @BeforeRetry(methodName = "logRetryAttempt")
    public void importantOperation() throws Exception {
        performCriticalTask();
    }
    
    public void logRetryAttempt() {
        logger.warn("Retrying important operation due to failure");
        metrics.incrementRetryCounter("important-operation");
    }
}

// Custom before retry handler
public class RetryLoggingHandler implements BeforeRetryHandler {
    @Inject
    Logger logger;
    
    @Override
    public void handle(InvocationContext context) {
        String methodName = context.getMethod().getName();
        Throwable failure = context.getFailure();
        logger.info("Retrying method {} due to {}", methodName, failure.getClass().getSimpleName());
    }
}

Types

Core Retry Types

// Time units for delays and durations
enum ChronoUnit {
    NANOS, MICROS, MILLIS, SECONDS, MINUTES, HOURS, HALF_DAYS, DAYS
}

// Invocation context for before retry handlers
interface InvocationContext {
    Method getMethod();
    Object[] getParameters();
    Object getTarget();
    Throwable getFailure();
    Map<String, Object> getContextData();
}

// Predicate for conditional retry
interface Predicate<T> {
    boolean test(T t);
}

Strategy Implementation Types

// Custom backoff strategy interface
interface CustomBackoffStrategy {
    /**
     * Calculate the next delay based on attempt index
     * @param attemptIndex Zero-based index of the retry attempt
     * @return Delay in milliseconds before next retry
     */
    long nextDelayInMillis(int attemptIndex);
}

// Before retry handler interface
interface BeforeRetryHandler {
    /**
     * Handle logic to execute before each retry attempt
     * @param context Invocation context with method and failure information
     */
    void handle(InvocationContext context);
}

Install with Tessl CLI

npx tessl i tessl/maven-io-quarkus--quarkus-smallrye-fault-tolerance

docs

asynchronous-strategies.md

bulkhead-strategies.md

circuit-breaker-strategies.md

configuration.md

fallback-strategies.md

index.md

programmatic-api.md

rate-limiting-strategies.md

retry-strategies.md

timeout-strategies.md

tile.json