开发者

Retry Task Framework

I have a number of situations where I need to retry a task n-ti开发者_JAVA百科mes if it fails (sometimes with some form of back-off-before-retry logic). Generally, if an exception is thrown, the task should be retried up to the max-retry count.

I can easily write something to do this fairly generically, but not wanting to re-invent the wheel I was wondering if anyone can recommend any frameworks for this. The only thing I have been able to find is: Ant Retry but I don't want to use Ant tasks directly in my application.

Thanks


Check out Failsafe (which I authored). It's a simple, zero-dependency library for performing retries, and supports synchronous and asynchronous retries, Java 8 integration, event listeners, integration with other async APIs, etc:

RetryPolicy retryPolicy = new RetryPolicy()
  .handle(ConnectException.class, SocketException.class);
  .withMaxRetries(3);

Connection connection = Failsafe.with(retryPolicy).get(() -> connect());

Doesn't get much easier.


You can use RetriableTasks as outlined in this post: Retrying Operations in Java. You can quite easily change its waiting algorithm if you like.

Sample code:

//creates a task which will retry 3 times with an interval of 5 seconds
RetriableTask r = new RetriableTask(3, 5000, new Callable(){
    public Object call() throws Exception{
        //put your code here
    }
});
r.call();


If you use Spring:

//import the necessary classes
import org.springframework.batch.retry.RetryCallback;
import org.springframework.batch.retry.RetryContext;
import org.springframework.batch.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.batch.retry.policy.SimpleRetryPolicy;
import org.springframework.batch.retry.support.RetryTemplate;
...

// create the retry template
final RetryTemplate template = new RetryTemplate();
template.setRetryPolicy(new SimpleRetryPolicy(5));
final ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
backOffPolicy.setInitialInterval(1000L);
template.setBackOffPolicy(backOffPolicy);

// execute the operation using the retry template
template.execute(new RetryCallback<Remote>() {
  @Override
  public Remote doWithRetry(final RetryContext context) throws Exception {
    return (Remote) Naming.lookup("rmi://somehost:2106/MyApp");
  }
});

Original blog post


If you are using Spring, it is very simple using Spring Retry Library.

Now, Spring Retry is an individual library (earlier it was part of Spring Batch) framework.

Step1: Add spring retry dependency.

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.1.2.RELEASE</version>
</dependency>

Step2: Add @EnableRetry annotation to your class which contains main() method of your application or into any of your @Configuration class .

Step3: Add @Retryable annotation to your method which you want to retry/call again, in case of exceptions.

@Retryable(maxAttempts=5,backoff = @Backoff(delay = 3000))
public void retrySomething() throws Exception{
    logger.info("printSomething{} is called");
    throw new SQLException();
}

This @Retryable annotation will retry/call retrySomething() 5 times (including the 1st failure).

Current thread will wait for 3000 ms or 3 seconds between next retry.


I have one answer already, but it was three years ago and I have to add that now I absolutley love guava-retrying project. Let me just show you the code.

Callable<Boolean> callable = new Callable<Boolean>() {
    public Boolean call() throws Exception {
        return true; // do something useful here
    }
};

Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
        .retryIfResult(Predicates.<Boolean>isNull())
        .retryIfExceptionOfType(IOException.class)
        .retryIfRuntimeException()
        .withStopStrategy(StopStrategies.stopAfterAttempt(3))
        .build();
try {
    retryer.call(callable);
} catch (RetryException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}


One option to factor this out of your codebase is to use the command pattern between the components of your application. Once you turn a call to a business method into an object, you can hand around the call easily and have an abstract RetryHandler that takes a command and retries it. This should be independent from the actual call and reusable.


I have implemented a pretty flexible retry utility here

You can retry any Callable with:

public static <T> T executeWithRetry(final Callable<T> what, final int nrImmediateRetries,
        final int nrTotalRetries, final int retryWaitMillis, final int timeoutMillis,
        final Predicate<? super T> retryOnReturnVal, final Predicate<Exception> retryOnException)

with immediate + delayed retries, with a max timeout, and retry either on decisions based on result or exception.

There are several other versions of this function with more or less flexibility.

I have written also a aspect that can be applied with annotations Retry Retry Aspect


You can use Quartz. Look at this Stack Overflow answer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜