I'm writing some reconnect logic to periodically attempt to establish a connection to a remote endpoint which went down. Essentially, the code looks like this:
public void establishConnection() {
try {
this.connection = newConnection();
} catch (IOException e) {
// connection failed, try again.
try { Thread.sleep(1000); } catch (InterruptedException e) {};
establishConnection();
}
}
I've solved this general problem with code similar to the above on many occasions, but I feel largely unsatisfied with the result. Is there a design pattern designed for dealing with this issue?
Shameless plug: I have implemented some classes to allow retrying operations. The library is not made available yet, but you may fork it on github.
And a fork exists.
It allows building a Retryer with various flexible strategies. For example:
Retryer retryer =
RetryerBuilder.newBuilder()
.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECOND))
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.retryIfExceptionOfType(IOException.class)
.build();
And you can then execute a callable (or several ones) with the Retryer:
retryer.call(new Callable<Void>() {
public Void call() throws IOException {
connection = newConnection();
return null;
}
}
You could try the Idempotent Retry Pattern.
I really like this Java 8 code from this blog and you don't need any extra library on your classpath.
You only need to pass a function to the retry class.
#Slf4j
public class RetryCommand<T> {
private int maxRetries;
RetryCommand(int maxRetries)
{
this.maxRetries = maxRetries;
}
// Takes a function and executes it, if fails, passes the function to the retry command
public T run(Supplier<T> function) {
try {
return function.get();
} catch (Exception e) {
log.error("FAILED - Command failed, will be retried " + maxRetries + " times.");
return retry(function);
}
}
private T retry(Supplier<T> function) throws RuntimeException {
int retryCounter = 0;
while (retryCounter < maxRetries) {
try {
return function.get();
} catch (Exception ex) {
retryCounter++;
log.error("FAILED - Command failed on retry " + retryCounter + " of " + maxRetries, ex);
if (retryCounter >= maxRetries) {
log.error("Max retries exceeded.");
break;
}
}
}
throw new RuntimeException("Command failed on all of " + maxRetries + " retries");
}
}
And to use it:
new RetryCommand<>(5).run(() -> client.getThatThing(id));
Using Failsafe (author here):
RetryPolicy retryPolicy = new RetryPolicy()
.retryOn(IOException.class)
.withMaxRetries(5)
.withDelay(1, TimeUnit.SECONDS);
Failsafe.with(retryPolicy).run(() -> newConnection());
No annotations, no magic, doesn't need to be a Spring app, etc. Just straightforward and simple.
I'm using AOP and Java annotations. There is a ready-made mechanism in jcabi-aspects (I'm a developer):
#RetryOnFailure(attempts = 3, delay = 1, unit = TimeUnit.SECONDS)
public void establishConnection() {
this.connection = newConnection();
}
ps. You can also try RetryScalar from Cactoos.
You can try spring-retry, it has a clean interface and it's easy to use.
Example:
#Retryable(maxAttempts = 4, backoff = #Backoff(delay = 500))
public void establishConnection() {
this.connection = newConnection();
}
In case of exception, it will retry (call) up to 4 times the method establishConnection() with a backoff policy of 500ms
You can also create a wrapper function that just does a loop over the intended operation and when is done just break out of the loop.
public static void main(String[] args) {
retryMySpecialOperation(7);
}
private static void retryMySpecialOperation(int retries) {
for (int i = 1; i <= retries; i++) {
try {
specialOperation();
break;
}
catch (Exception e) {
System.out.println(String.format("Failed operation. Retry %d", i));
}
}
}
private static void specialOperation() throws Exception {
if ((int) (Math.random()*100) % 2 == 0) {
throw new Exception("Operation failed");
}
System.out.println("Operation successful");
}
If you are using java 8, this may helps.
import java.util.function.Supplier;
public class Retrier {
public static <T> Object retry(Supplier<T> function, int retryCount) throws Exception {
while (0<retryCount) {
try {
return function.get();
} catch (Exception e) {
retryCount--;
if(retryCount == 0) {
throw e;
}
}
}
return null;
}
public static void main(String[] args) {
try {
retry(()-> {
System.out.println(5/0);
return null;
}, 5);
} catch (Exception e) {
System.out.println("Exception : " + e.getMessage());
}
}
}
Thanks,
Praveen R.
I'm using retry4j library. Test code example:
public static void main(String[] args) {
Callable<Object> callable = () -> {
doSomething();
return null;
};
RetryConfig config = new RetryConfigBuilder()
.retryOnAnyException()
.withMaxNumberOfTries(3)
.withDelayBetweenTries(5, ChronoUnit.SECONDS)
.withExponentialBackoff()
.build();
new CallExecutorBuilder<>().config(config).build().execute(callable);
}
public static void doSomething() {
System.out.println("Trying to connect");
// some logic
throw new RuntimeException("Disconnected"); // init error
// some logic
}
Here's a another approach to perform the retry. No libraries, no annotations, no extra implementations. Import java.util.concurrent.TimeUnit;
public static void myTestFunc() {
boolean retry = true;
int maxRetries = 5; //max no. of retries to be made
int retries = 1;
int delayBetweenRetries = 5; // duration between each retry (in seconds)
int wait = 1;
do {
try {
this.connection = newConnection();
break;
}
catch (Exception e) {
wait = retries * delayBetweenRetries;
pause(wait);
retries += 1;
if (retries > maxRetries) {
retry = false;
log.error("Task failed on all of " + maxRetries + " retries");
}
}
} while (retry);
}
public static void pause(int seconds) {
long secondsVal = TimeUnit.MILLISECONDS.toMillis(seconds);
try {
Thread.sleep(secondsVal);
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
there is nothing special in retrying at all - take this class as example http://www.docjar.com/html/api/org/springframework/jms/listener/DefaultMessageListenerContainer.java.html
As you can see even spring developers still writing code for retry-ing - line 791...
there is no such special pattern AFAIK..
What i can advice to deal with resources is to take apache commons pool library - check this http://commons.apache.org/pool/apidocs/org/apache/commons/pool/impl/GenericObjectPool.html and visit http://commons.apache.org/pool
I have wrote my custom annotation. Maybe you can use this annotation.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface RetryOperation {
int retryCount();
int waitSeconds();
}
#Slf4j
#Aspect
#Component
public class RetryOperationAspect {
#Around(value = "#annotation(com.demo.infra.annotation.RetryOperation)")
public Object retryOperation(ProceedingJoinPoint joinPoint) throws Throwable {
Object response = null;
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
RetryOperation annotation = method.getAnnotation(RetryOperation.class);
int retryCount = annotation.retryCount();
int waitSeconds = annotation.waitSeconds();
boolean successful = false;
do {
try {
response = joinPoint.proceed();
successful = true;
} catch (Exception e) {
log.error("Operation failed, retries remaining: {}", retryCount);
retryCount--;
if (retryCount < 0) {
throw e;
}
if (waitSeconds > 0) {
log.warn("Waiting for {} second(s) before next retry", waitSeconds);
Thread.sleep(waitSeconds * 1000L);
}
}
} while (!successful);
return response;
}
}
#RetryOperation(retryCount = 5, waitSeconds = 1)
public void method() {
}
Related
I am trying to write a simple function that long-polls multiple messages tothe downstream dependency without exhausting it and only exist when all messages succeeded.
I came up with a way to wrap each message polling into a callable and use a ExecutorService to submit a list of callables.
public void poll(final List<Long> messageIdList) {
ExecutorService executorService = Executors.newFixedThreadPool(messageIdList.size());
List<MessageStatusCallable> callables = messageIdList.stream()
.map(messageId -> new MessageStatusCallable(messageId)).collect(Collectors.toList());
boolean allSuccess = false;
try {
allSuccess = executorService.invokeAll(callables).stream().allMatch(success -> {
try {
return success.get().equals(Boolean.TRUE);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
} catch (ExecutionException e) {
e.printStackTrace();
return false;
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private class MessageStatusCallable implements Callable<Boolean> {
private Long messageId;
public MessageStatusCallable(Long messageId) {
this.messageId = messageId;
}
/**
* Computes a result, or throws an exception if unable to do so.
*
* #return computed result
* #throws Exception if unable to compute a result
*/
#Override
public Boolean call() throws Exception {
String messageStatus = downstreamService.getMessageStatus(messageId);
while(messageStatus == null || !messageStatus.equals( STATUS_VALUE_SUCCEEDED) {
messageStatus = messageLogToControlServer.getMessageStatus(messageId);
Thread.sleep(TimeUnit.MICROSECONDS.toMillis(100));
}
LOG.info("Message: " + messageId + " Succeded");
return true;
}
}
I wonder if there is a better way to achieve this since Thread.sleep is blocking and ugly.
I'm not sure this is the best solution but it occurred to me you could use a CountDownLatch and ScheduledExecutorService.
public void poll(final List<Long> messageIdList) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(messageIdList.size());
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(POOL_SIZE);
try {
for (Long messageId : messageIdList) {
MessageStatusCallable callable = new MessageStatusCallable(messageId, latch);
executorService.scheduleWithFixedDelay(
() -> {
String messageStatus = downstreamService.getMessageStatus(messageId);
if (STATUS_VALUE_SUCCEEDED.equals(messageStatus)) {
latch.countDown();
throw new CompletionException("Success - killing the task", null);
}
},
0, 100, TimeUnit.MILLISECONDS);
}
latch.await();
} finally {
executorService.shutdown();
}
}
I probably also wouldn't have the Runnable as a lambda other than for brevity in the answer.
I have made this abstract class to automatically retry network calls if some exception is thrown.
I take care to not retry after InterruptedException &
UnknownHostException.
I retry 5 times. After each failure
I perform an exponential back off, starting from 300ms going upto
1500ms.
public abstract class AutoRetry {
private Object dataToReturn = null;
public Object getDataToReturn() {
return this.dataToReturn;
}
public AutoRetry() {
short retry = -1;
while (retry++ < StaticData.NETWORK_RETRY) {
try {
Thread.sleep(retry * StaticData.NETWORK_CALL_WAIT);
this.dataToReturn = doWork();
break;
} catch (InterruptedException | UnknownHostException e) {
e.printStackTrace();
this.dataToReturn = null;
return;
} catch (IOException e) {
e.printStackTrace();
}
}
}
protected abstract Object doWork() throws IOException;
}
I use it as follows :
final Object dataAfterWork = new AutoRetry() {
#Override
protected Object doWork() throws IOException {
return; //a network call which returns something
}
}.getDataToReturn();
So is this implementation good/correct ?
EDIT
moved to https://codereview.stackexchange.com/questions/87686
This looks pretty good, but I would split the running task from the retry. Also use generics, don't just throw Object about.
Use a Java 8 lambda and the return of the method:
public static <T> Optional<T> doWithRetry(final Supplier<T> t) {
for (int retry = 0; retry <= StaticData.NETWORK_RETRY; ++retry) {
try {
Thread.sleep(retry * StaticData.NETWORK_CALL_WAIT);
return Optional.of(t.get());
} catch (InterruptedException | UnknownHostException e) {
LOGGER.log(Level.SEVERE, "Call failed.", e);
return Optional.empty();
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Call failed. Retry.", e);
}
}
LOGGER.log(Level.SEVERE, "Call failed. Retries exceeded.");
return Optional.empty();
}
Also, use a real logger, not printStackTrace...
Usage:
final String data = doWithRetry(() -> {
//do stuff
});
If your lambda needs to throw an exception, you'll need to define your own #FunctionalInterface:
#FunctionalInterface
interface StuffDoer<T> {
T doStuff() throws Exception;
}
And use that in the method signature, you'll need to handle generic Exception.
Pre-Java 8 usage:
final String data = doWithRetry(new StuffDoer<T>() {
#Override
public T get() throws Exception {
return null;
}
});
My Java application requires a retry logic on remote calls failures.
These remote calls are:
scattered all over the application
pertain to different Remote Service classes.
Also, the retry logic may have varying retry interval and varying retry attempts.
I need a generic retry() implementation which can make appropriate method calls depending on from where it is called. Below is a simple code illustration of I am looking for. I know we can attempt to do this using java reflection, but, is there a framework or an open source available somewhere which is read-to-use?
try {
ClassA objA = remoteServiceA.call(paramA1, paramA2, ...);
} catch (Exception e){
ClassA objA = (ClassA)retry(remoteService, listOfParams, ..); // generic method call
}
..
try {
ClassB objB = remoteServiceB.call(paramB1, paramB2, ...);
} catch (Exception e){
ClassA objB = (ClassB)retry(remoteService, listOfParams, ..); // generic method call
}
As already suggested, you should use AOP and Java annotations. I would recommend a read-made mechanism from jcabi-aspects (I'm a developer):
#RetryOnFailure(attempts = 3, delay = 5)
public String load(URL url) {
return url.openConnection().getContent();
}
Read also this blog post: http://www.yegor256.com/2014/08/15/retry-java-method-on-exception.html
Update: Check RetryFunc from Cactoos.
This is a book example of where aspectj (or aop in general) can be used, see 8.2.7 Example in Spring documentation and 5 Reasons Java Developers Should Learn and Use AspectJ.
Basically an aspect intercepts all calls to given methods (specified using annotation, naming convention, whatever) and retries.
Assume you have a method, that need to retied at every 500ms and upto 5 times.
Current class:
public class RemoteCaller{
Service serviceCaller;
public void remoteCall(String message) {
serviceCaller.updateDetails( this.message);
return null;
}
}
Modified approach:
public class RetriableHelper<T> implements Callable<T> {
private Callable<T> task;
private int numberOfRetries;
private int numberOfTriesLeft;
private long timeToWait;
public RetriableHelper(int numberOfRetries, long timeToWait, Callable<T> task) {
this.numberOfRetries = numberOfRetries;
numberOfTriesLeft = numberOfRetries;
this.timeToWait = timeToWait;
this.task = task;
}
public T call() throws Exception {
while (true) {
try {
return task.call();
} catch (InterruptedException e) {
throw e;
} catch (CancellationException e) {
throw e;
} catch (Exception e) {
numberOfTriesLeft--;
if (numberOfTriesLeft == 0) {
throw e;
}
Thread.sleep(timeToWait);
}
}
}
}
Backend system/remote call class:
public class RemoteCaller{
Service serviceCaller;
public void remoteCall(String message) {
class RemoteCallable implements Callable<Void> {
String message;
public RemoteCallable( String message)
{
this.message = message;
}
public Void call() throws Exception{
serviceCaller.updateDetails( this.message);
return null;
}
}
RetriableHelper<Void> retriableHelper = new RetriableHelper<Void>(5, 500, new RemoteCallable( message));
try {
retriableHelper.call();
} catch (Exception e) {
throw e;
}
}
}
enter link description here Spring has a retry annotation which servers the purpose
Step 1: Add following dependency to your POM
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.1.5.RELEASE</version>
</dependency>
Step 2: Enabling Spring Retry
To enable Spring Retry in an application, we need to add the #EnableRetry annotation to our #Configuration class:
Ex:
#Configuration
#EnableRetry
public class AppConfig { ... }
Step 3: To add retry functionality to methods, #Retryable can be used:
Ex:
#Service
public interface MyService {
#Retryable(
value = { SQLException.class },
maxAttempts = 2,
backoff = #Backoff(delay = 5000))
void retryService(String sql) throws SQLException;
...
}
Step 4.The #Recover annotation is used to define a separate recovery method when a #Retryable method fails with a specified exception:
Ex:
#Service
public interface MyService {
...
#Recover
void recover(SQLException e, String sql);
}
See Url for more details : http://www.baeldung.com/spring-retry
where do you get the services from? use a factory to Proxy the service you get from the original factory. The proxy can then implement the retry transparently. See the java Proxy/ProxyGenerators in reflection.
If you are using spring , then better go with Aspects.
Otherwise, below sample solution can work:
public class Test
{
public static void main(String[] args) throws Exception
{
Test test = new Test();
test.toRunFirst("Hello! This is normal invocation");
runWithRetry(test, "toRunFirst", "Hello! This is First, called with retry");
runWithRetry(test, "toRunSecond", "Hello! This is Second, called with retry");
}
public void toRunFirst(String s) {
System.out.println(s);
}
public void toRunSecond(String s) {
System.out.println(s);
}
public static Object runWithRetry(Object obj, String methodName, Object... args) throws Exception
{
Class<?>[] paramClass = new Class<?>[args.length];
for(int i=0; i< args.length; i++) {
paramClass[i] = args[i].getClass();
}
Method method = obj.getClass().getDeclaredMethod(methodName, paramClass);
int retryCount = 2;
for(int i=0; i< retryCount; i++) {
try {
return method.invoke(obj, args);
}
catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
I did not find what I needed so there is mine.
The main feature is that it throws the type of Exception you need when maxRetries is reached so you can catch it in the call.
import org.apache.log4j.Logger;
public class TaskUtils {
public static <E extends Throwable> void retry(int maxRetries, Task<E> task) throws E {
retry(maxRetries, 0, null, task);
}
public static <E extends Throwable> void retry(int maxRetries, long waitTimeMs, Logger logger, Task<E> task) throws E {
while (maxRetries > 0) {
maxRetries--;
try {
task.run();
} catch (Exception e) {
if (maxRetries == 0) {
try {
throw e;
} catch (Exception ignored) { // can't happen but just in case we wrap it in
throw new RuntimeException(e);
}
}
if (logger != null)
logger.warn("Attempt " + maxRetries + " failed", e);
try {
Thread.sleep(waitTimeMs);
} catch (InterruptedException ignored) {
}
}
}
}
public interface Task<E extends Throwable> {
void run() throws E;
}
}
Usage :
TaskUtils.retry(3, 500, LOGGER, () -> stmClickhouse.execute(
"ALTER TABLE `" + database + "`.`" + table.getName() + "` ON CLUSTER " + clusterName + allColumnsSql
));
add it into pom.xml
<dependency>
<groupId>org.deking.utils</groupId>
<artifactId>retry</artifactId>
<version>0.0.2-SNAPSHOT</version>
</dependency>
new Retry<String>()
.maxOperationWaitTime(30_000)//Max operation wait time during a single operation
.retryIntervalTime(1_000)//Interval time between two operations
.maxRetryTimes(3)//Retry times when operation failed(or timeout) at the first time
.operation(() -> {
//your operation
return "success!";
})
.judgement(t -> (t == null || t.isEmpty()))//add your judgement whether the operation should be retry(Operation should return a value)
.execute();
If you want add retry config annotation on method,and call it:
class RetryTests{
#RetryConfig( maxRetryTimes=1)
public static String TestAnnotation() {
return "aaa";
}
public static void main(String[] args) {
try {
new Retry<String>()
.of(RetryTest.class.getMethod("TestAnnotation"),null)
.judgement(r -> r.equals("aaa"))
.execute();
} catch (NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I'm using a third party Java library to interact with a REST API. The REST API can sometimes take a long time to respond, eventually resulting in a java.net.ConnectException being thrown.
I'd like to shorten the timeout period but have no means of modifying the third party library.
I'd like to apply some form of timeout control around the calling of a Java method so that I can determine at what point to give up waiting.
This doesn't relate directly to network timeouts. I'd like to be able to try and perform an operation and be able to give up after a specified wait time.
The following is by no means valid Java but does conceptually demonstrate what I'd like to achieve:
try {
Entity entity = new Entity();
entity.methodThatMakesUseOfRestApi();
} catch (<it's been ages now, I don't want to wait any longer>) {
throw TimeoutException();
}
I recommend TimeLimiter from Google Guava library.
This is probably the current way how this should be done with plain Java:
public String getResult(final RESTService restService, String url) throws TimeoutException {
// should be a field, not a local variable
ExecutorService threadPool = Executors.newCachedThreadPool();
// Java 8:
Callable<String> callable = () -> restService.getResult(url);
// Java 7:
// Callable<String> callable = new Callable<String>() {
// #Override
// public String call() throws Exception {
// return restService.getResult(url);
// }
// };
Future<String> future = threadPool.submit(callable);
try {
// throws a TimeoutException after 1000 ms
return future.get(1000, TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
throw new RuntimeException(e.getCause());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new TimeoutException();
}
}
There is no general timeout mechanism valid for arbitrary operations.
While... there is one... by using Thread.stop(Throwable). It works and it's thread safe, but your personal safety is in danger when the angry mob confronts you.
// realizable
try
{
setTimeout(1s); // 1
... any code // 2
cancelTimeout(); // 3
}
catch(TimeoutException te)
{
// if (3) isn't executed within 1s after (1)
// we'll get this exception
}
Now we have our nice CompletableFuture , here an application to achieve what was asked.
CompletableFuture.supplyAsync(this::foo).get(15, TimeUnit.SECONDS)
You could use a Timer and a TimerTask.
Here's a utility class I wrote, which should do the trick unless I've missed something. Unfortunately it can only return generic Objects and throw generic Exceptions. Others may have better ideas on how to achieve this.
public abstract class TimeoutOperation {
long timeOut = -1;
String name = "Timeout Operation";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getTimeOut() {
return timeOut;
}
public void setTimeOut(long timeOut) {
this.timeOut = timeOut;
}
public TimeoutOperation (String name, long timeout) {
this.timeOut = timeout;
}
private Throwable throwable;
private Object result;
private long startTime;
public Object run () throws TimeoutException, Exception {
Thread operationThread = new Thread (getName()) {
public void run () {
try {
result = doOperation();
} catch (Exception ex) {
throwable = ex;
} catch (Throwable uncaught) {
throwable = uncaught;
}
synchronized (TimeoutOperation.this) {
TimeoutOperation.this.notifyAll();
}
}
public synchronized void start() {
super.start();
}
};
operationThread.start();
startTime = System.currentTimeMillis();
synchronized (this) {
while (operationThread.isAlive() && (getTimeOut() == -1 || System.currentTimeMillis() < startTime + getTimeOut())) {
try {
wait (1000L);
} catch (InterruptedException ex) {}
}
}
if (throwable != null) {
if (throwable instanceof Exception) {
throw (Exception) throwable;
} else if (throwable instanceof Error) {
throw (Error) throwable;
}
}
if (result != null) {
return result;
}
if (System.currentTimeMillis() > startTime + getTimeOut()) {
throw new TimeoutException("Operation '"+getName()+"' timed out after "+getTimeOut()+" ms");
} else {
throw new Exception ("No result, no exception, and no timeout!");
}
}
public abstract Object doOperation () throws Exception;
public static void main (String [] args) throws Throwable {
Object o = new TimeoutOperation("Test timeout", 4900) {
public Object doOperation() throws Exception {
try {
Thread.sleep (5000L);
} catch (InterruptedException ex) {}
return "OK";
}
}.run();
System.out.println(o);
}
}
static final int NUM_TRIES =4;
int tried =0;
boolean result =false;
while (tried < NUM_TRIES && !result)
{
try {
Entity entity = new Entity();
result = entity.methodThatMakesUseOfRestApi();
}
catch (<it's been ages now, I don't want to wait any longer>) {
if ( tried == NUM_TRIES)
{
throw new TimeoutException();
}
}
tried++;
Thread.sleep(4000);
}
I have a single thread trying to connect to a database using JDBCTemplate as follows:
JDBCTemplate jdbcTemplate = new JdbcTemplate(dataSource);
try{
jdbcTemplate.execute(new CallableStatementCreator() {
#Override
public CallableStatement createCallableStatement(Connection con)
throws SQLException {
return con.prepareCall(query);
}
}, new CallableStatementCallback() {
#Override
public Object doInCallableStatement(CallableStatement cs)
throws SQLException {
cs.setString(1, subscriberID);
cs.execute();
return null;
}
});
} catch (DataAccessException dae) {
throw new CougarFrameworkException(
"Problem removing subscriber from events queue: "
+ subscriberID, dae);
}
I want to make sure that if the above code throws DataAccessException or SQLException, the thread waits a few seconds and tries to re-connect, say 5 more times and then gives up. How can I achieve this? Also, if during execution the database goes down and comes up again, how can i ensure that my program recovers from this and continues running instead of throwing an exception and exiting?
Thanks in advance.
Try this. My considerations are : run a loop until the statements executed successfully. If there is a failure, tolerate the failure for 5 times and each time it will wait for 2 seconds for the next execution.
JDBCTemplate jdbcTemplate = new JdbcTemplate(dataSource);
boolean successfullyExecuted = false;
int failCount = 0;
while (!successfullyExecuted){
try{
jdbcTemplate.execute(new CallableStatementCreator() {
#Override
public CallableStatement createCallableStatement(Connection con)
throws SQLException {
return con.prepareCall(query);
}
}, new CallableStatementCallback() {
#Override
public Object doInCallableStatement(CallableStatement cs)
throws SQLException {
cs.setString(1, subscriberID);
cs.execute();
return null;
}
});
successfullyExecuted = true;
} catch (DataAccessException dae) {
if (failedCount < 5){
failedCount ++;
try{java.lang.Thread.sleep(2 * 1000L); // Wait for 2 seconds
}catch(java.lang.Exception e){}
}else{
throw new CougarFrameworkException(
"Problem removing subscriber from events queue: "
+ subscriberID, dae);
}
} catch (java.sql.SQLException sqle){
if (failedCount < 5){
failedCount ++;
}else{
try{java.lang.Thread.sleep(2 * 1000L); // Wait for 2 seconds
}catch(java.lang.Exception e){}
throw new CougarFrameworkException(
"Problem removing subscriber from events queue: "
+ subscriberID, dae);
}
}
}
It might be worthwhile for you to look into Spring's Aspect support. What you're describing is retry with (constant) backoff, and chances are you'll eventually need it somewhere else, be it talking to a web service, an email server, or any other complicated system susceptible to transient failures.
For instance, this simple method invokes the underlying method up to maxAttempts times whenever an exception is thrown, unless it is a subclass of a Throwable listed in noRetryFor.
private Object doRetryWithExponentialBackoff(ProceedingJoinPoint pjp, int maxAttempts,
Class<? extends Throwable>[] noRetryFor) throws Throwable {
Throwable lastThrowable = null;
for (int attempts = 0; attempts < maxAttempts; attempts++) {
try {
pauseExponentially(attempts, lastThrowable);
return pjp.proceed();
} catch (Throwable t) {
lastThrowable = t;
for (Class<? extends Throwable> noRetryThrowable : noRetryFor) {
if (noRetryThrowable.isAssignableFrom(t.getClass())) {
throw t;
}
}
}
}
throw lastThrowable;
}
private void pauseExponentially(int attempts, Throwable lastThrowable) {
if (attempts == 0)
return;
long delay = (long) (Math.random() * (Math.pow(4, attempts) * 100L));
log.warn("Retriable error detected, will retry in " + delay + "ms, attempts thus far: "
+ attempts, lastThrowable);
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
// Nothing we need to do here
}
}
This advice could be applied to any bean you wish using Spring's Aspect support. See http://static.springsource.org/spring/docs/2.5.x/reference/aop.html for more details.
something like this:
private int retries;
/**
* Make this configurable.
*/
public void setRetries(final int retries) {
Assert.isTrue(retries > 0);
this.retries = retries;
}
public Object yourMethod() {
final int tries = 0;
Exception lastException = null;
for (int i = 0; i < this.retries; i++) {
try {
return jdbcTemplate.execute ... (your code here);
} catch (final SQLException e) {
lastException = e;
} catch (final DataAccessException e) {
lastException = e;
}
}
throw lastException;
}
How about writting an aspect (DBRetryAspect) over it;It will be more transparent.