Java Retry implement

There are many cases in which you may wish to retry an operation a certain number of times. Examples are database failures, network communication failures or file IO problems.

Approach 1
This is the traditional approach and involves a counter and a loop.

final int numberOfRetries = 5 ;
final long timeToWait = 1000 ;
 
for ( int i= 0 ; i<numberOfRetries; i++) {
  //perform the operation
  try {
   Naming.lookup( "rmi://localhost:2106/MyApp" );
   break ;
  }
  catch (Exception e) {
   logger.error( "Retrying..." ,e);
   try {
    Thread.sleep(timeToWait);
   }
   catch (InterruptedException i) {
   }
  }
}

Approach 2
In this approach, we hide the retry counter in a separate class called RetryStrategy and call it like this:

public class RetryStrategy
{
  public static final int DEFAULT_NUMBER_OF_RETRIES = 5 ;
  public static final long DEFAULT_WAIT_TIME = 1000 ;
 
  private int numberOfRetries; //total number of tries
  private int numberOfTriesLeft; //number left
  private long timeToWait; //wait interval
 
  public RetryStrategy()
  {
   this (DEFAULT_NUMBER_OF_RETRIES, DEFAULT_WAIT_TIME);
  }
 
  public RetryStrategy( int numberOfRetries, long timeToWait)
  {
   this .numberOfRetries = numberOfRetries;
   numberOfTriesLeft = numberOfRetries;
   this .timeToWait = timeToWait;
  }
 
  /**
   * @return true if there are tries left
   */
  public boolean shouldRetry()
  {
   return numberOfTriesLeft > 0 ;
  }
 
  /**
   * This method should be called if a try fails.
   *
   * @throws RetryException if there are no more tries left
   */
  public void errorOccured() throws RetryException
  {
   numberOfTriesLeft --;
   if (!shouldRetry())
   {
    throw new RetryException(numberOfRetries +
      " attempts to retry failed at " + getTimeToWait() +
      "ms interval" );
   }
   waitUntilNextTry();
  }
 
  /**
   * @return time period between retries
   */
  public long getTimeToWait()
  {
   return timeToWait ;
  }
 
  /**
   * Sleeps for the duration of the defined interval
   */
  private void waitUntilNextTry()
  {
   try
   {
    Thread.sleep(getTimeToWait());
   }
   catch (InterruptedException ignored) {}
  }
 
  public static void main(String[] args) {
   RetryStrategy retry = new RetryStrategy();
   while (retry.shouldRetry()) {
    try {
     Naming.lookup( "rmi://localhost:2106/MyApp" );
     break ;
    }
    catch (Exception e) {
     try {
      retry.errorOccured();
     }
     catch (RetryException e1) {
      e.printStackTrace();
     }
    }
   }
  }
}

Approach 3
Approach 2, although cleaner, hasn't really reduced the number of lines of code we have to write. In the next approach, we hide the retry loop and all logic in a separate class called RetriableTask. We make the operation that we are going to retry Callable and wrap it in a RetriableTask which then handles all the retrying for us, behind-the-scenes:

public class RetriableTask<T> implements Callable<T> {
 
  private Callable<T> task;
  public static final int DEFAULT_NUMBER_OF_RETRIES = 5 ;
  public static final long DEFAULT_WAIT_TIME = 1000 ;
 
  private int numberOfRetries; // total number of tries
  private int numberOfTriesLeft; // number left
  private long timeToWait; // wait interval
 
  public RetriableTask(Callable<T> task) {
   this (DEFAULT_NUMBER_OF_RETRIES, DEFAULT_WAIT_TIME, task);
  }
 
  public RetriableTask( 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 new RetryException(numberOfRetries +
      " attempts to retry failed at " + timeToWait +
      "ms interval" , e);
     }
     Thread.sleep(timeToWait);
    }
   }
  }
 
  public static void main(String[] args) {
   Callable<Remote> task = new Callable<Remote>() {
    public Remote call() throws Exception {
     String url= "rmi://localhost:2106/MyApp" ;
     return (Remote) Naming.lookup(url);
    }
   };
 
   RetriableTask<Remote> r = new RetriableTask<Remote>(task);
   try {
    r.call();
   }
   catch (Exception e) {
    e.printStackTrace();
   }
  }
}

Also see:

References:

你可能感兴趣的:(java)