Boost Massive Task Retries with Fast‑Retry: A High‑Performance Async Framework
This article introduces Fast‑Retry, a high‑performance asynchronous multi‑task retry framework for Java, compares its speed against Spring‑Retry and Guava‑Retry, and provides step‑by‑step code examples for dependency setup, task creation, annotation usage, and custom retry annotations.
Introduction
When you need to poll and retry identity information for millions of users, traditional single‑task synchronous retry frameworks such as Spring‑Retry or Guava‑Retry become impractical, even with many machines or threads. Fast‑Retry is designed specifically for this massive‑scale scenario.
Fast‑Retry Overview
Fast‑Retry is a high‑performance multi‑task retry framework that supports asynchronous retries for millions of tasks, offers both programmatic and annotation‑based usage, and allows custom result‑based retry logic.
Performance Comparison
The following table shows the execution time for different task counts when using Fast‑Retry, Spring‑Retry, and Guava‑Retry. Fast‑Retry consistently completes in around 10 seconds even for 1 million tasks, while the other frameworks take orders of magnitude longer.
Task Count
FastRetry
Spring‑Retry
Guava‑Retry
1
10 s
10 s
10 s
10
10.066 s
20.092 s
20.078 s
50
10.061 s
70.186 s
70.168 s
100
10.077 s
130.33 s
130.31 s
500
10.154 s
631.420 s
631.53 s
1 000
10.237 s
1254.78 s
1256.28 s
5 000
10.482 s
≈6 250 s
≈6 250 s
10 000
10.686 s
≈12 520 s
≈12 520 s
100 000
13.71 s
≈125 000 s
≈125 000 s
500 000
28.89 s
≈625 000 s
≈625 000 s
1 000 000
58.05 s
≈1 250 000 s
≈1 250 000 s
Quick Start
Dependency
<dependency>
<groupId>io.github.burukeyou</groupId>
<artifactId>fast-retry-all</artifactId>
<version>0.2.0</version>
</dependency>Building Retry Tasks
There are three main ways to construct retry tasks. For simple usage, prefer FastRetryBuilder or the @FastRetry annotation.
Using RetryQueue Directly
ExecutorService executorService = Executors.newFixedThreadPool(8);
RetryQueue queue = new FastRetryQueue(executorService);
RetryTask<String> task = new RetryTask<String>() {
int result = 0;
// Interval before next retry
@Override
public long waitRetryTime() { return 2000; }
// Retry logic
@Override
public boolean retry() { return ++result < 5; }
// Result after retries
@Override
public String getResult() { return result + ""; }
};
CompletableFuture<String> future = queue.submit(task);
log.info("Task finished, result:{}", future.get());Using FastRetryBuilder
RetryResultPolicy<String> resultPolicy = result -> result.equals("444");
FastRetryer<String> retryer = FastRetryBuilder.<String>builder()
.attemptMaxTimes(3)
.waitRetryTime(3, TimeUnit.SECONDS)
.retryIfException(true)
.retryIfExceptionOfType(TimeoutException.class)
.exceptionRecover(true)
.resultPolicy(resultPolicy)
.build();
CompletableFuture<String> future = retryer.submit(() -> {
log.info("retry");
if (0 < 10) {
throw new TimeoutException("test");
}
return "444";
});
String o = future.get();
log.info("Result {}", o);Using @FastRetry Annotation
@FastRetry(retryWait = @RetryWait(delay = 2))
public String retryTask() {
return "success";
}
@FastRetry(retryWait = @RetryWait(delay = 2))
public CompletableFuture<String> retryTaskAsync() {
return CompletableFuture.completedFuture("success");
}Custom Retry Annotation
If the built‑in annotation does not meet your needs, you can define your own annotation, mark it with @FastRetry, specify a custom AnnotationRetryTaskFactory, and implement the task‑building logic. The default implementation is FastRetryAnnotationRetryTaskFactory.
Usage Recommendations
Regardless of the construction method, it is recommended to use asynchronous retry (returning CompletableFuture) and handle the result with whenComplete for non‑blocking execution.
Comparison Case Study
A weather‑service retry task was executed for 1 000 cities. Using Spring‑Retry took about 1 256 seconds, while Fast‑Retry completed in roughly 10 seconds, demonstrating the dramatic performance advantage of asynchronous multi‑task retry.
// Fast‑Retry weather service
@FastRetry(maxAttempts = 100, retryWait = @RetryWait(delay = 2, timeUnit = TimeUnit.SECONDS))
public CompletableFuture<WeatherResult> getFutureWeatherForCompare(String cityName) {
log.info("Fast‑Retry attempt {} for city {}", ++index, cityName);
WeatherResult weather = WeatherServer.getWeather(cityName);
if (weather == null) {
throw new RuntimeException("simulate exception for retry");
}
return FastRetryBuilder.of(weather);
}
// Spring‑Retry equivalent
@Retryable(maxAttempts = 100, backoff = @Backoff(delay = 2000))
public WeatherResult getSpringWeatherForCompare(String cityName) {
log.info("Spring‑Retry attempt {} for city {}", ++index, cityName);
WeatherResult weather = WeatherServer.getWeather(cityName);
if (weather == null) {
throw new RuntimeException("simulate exception for retry");
}
return weather;
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
