http://fahdshariff.blogspot.in/2009/08/retrying-operations-in-java.html
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.
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.
1: final int numberOfRetries = 5 ;
2: final long timeToWait = 1000 ;
3:
4: for (int i=0; i<numberOfRetries; i++) {
5: //perform the operation
6: try {
7: Naming.lookup("rmi://localhost:2106/MyApp");
8: break;
9: }
10: catch (Exception e) {
11: logger.error("Retrying...",e);
12: try {
13: Thread.sleep(timeToWait);
14: }
15: catch (InterruptedException i) {
16: }
17: }
18: }
Approach 2
In this approach, we hide the retry counter in a separate class called
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
In this approach, we hide the retry counter in a separate class called
RetryStrategy
and call it like this: 1: public class RetryStrategy
2: {
3: public static final int DEFAULT_NUMBER_OF_RETRIES = 5;
4: public static final long DEFAULT_WAIT_TIME = 1000;
5:
6: private int numberOfRetries; //total number of tries
7: private int numberOfTriesLeft; //number left
8: private long timeToWait; //wait interval
9:
10: public RetryStrategy()
11: {
12: this(DEFAULT_NUMBER_OF_RETRIES, DEFAULT_WAIT_TIME);
13: }
14:
15: public RetryStrategy(int numberOfRetries, long timeToWait)
16: {
17: this.numberOfRetries = numberOfRetries;
18: numberOfTriesLeft = numberOfRetries;
19: this.timeToWait = timeToWait;
20: }
21:
22: /**
23: * @return true if there are tries left
24: */
25: public boolean shouldRetry()
26: {
27: return numberOfTriesLeft > 0;
28: }
29:
30: /**
31: * This method should be called if a try fails.
32: *
33: * @throws RetryException if there are no more tries left
34: */
35: public void errorOccured() throws RetryException
36: {
37: numberOfTriesLeft --;
38: if (!shouldRetry())
39: {
40: throw new RetryException(numberOfRetries +
41: " attempts to retry failed at " + getTimeToWait() +
42: "ms interval");
43: }
44: waitUntilNextTry();
45: }
46:
47: /**
48: * @return time period between retries
49: */
50: public long getTimeToWait()
51: {
52: return timeToWait ;
53: }
54:
55: /**
56: * Sleeps for the duration of the defined interval
57: */
58: private void waitUntilNextTry()
59: {
60: try
61: {
62: Thread.sleep(getTimeToWait());
63: }
64: catch (InterruptedException ignored) {}
65: }
66:
67: public static void main(String[] args) {
68: RetryStrategy retry = new RetryStrategy();
69: while (retry.shouldRetry()) {
70: try {
71: Naming.lookup("rmi://localhost:2106/MyApp");
72: break;
73: }
74: catch (Exception e) {
75: try {
76: retry.errorOccured();
77: }
78: catch (RetryException e1) {
79: e.printStackTrace();
80: }
81: }
82: }
83: }
84: }
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:1: public class RetriableTask<T> implements Callable<T> {
2:
3: private Callable<T> task;
4: public static final int DEFAULT_NUMBER_OF_RETRIES = 5;
5: public static final long DEFAULT_WAIT_TIME = 1000;
6:
7: private int numberOfRetries; // total number of tries
8: private int numberOfTriesLeft; // number left
9: private long timeToWait; // wait interval
10:
11: public RetriableTask(Callable<T> task) {
12: this(DEFAULT_NUMBER_OF_RETRIES, DEFAULT_WAIT_TIME, task);
13: }
14:
15: public RetriableTask(int numberOfRetries, long timeToWait,
16: Callable<T> task) {
17: this.numberOfRetries = numberOfRetries;
18: numberOfTriesLeft = numberOfRetries;
19: this.timeToWait = timeToWait;
20: this.task = task;
21: }
22:
23: public T call() throws Exception {
24: while (true) {
25: try {
26: return task.call();
27: }
28: catch (InterruptedException e) {
29: throw e;
30: }
31: catch (CancellationException e) {
32: throw e;
33: }
34: catch (Exception e) {
35: numberOfTriesLeft--;
36: if (numberOfTriesLeft == 0) {
37: throw new RetryException(numberOfRetries +
38: " attempts to retry failed at " + timeToWait +
39: "ms interval", e);
40: }
41: Thread.sleep(timeToWait);
42: }
43: }
44: }
45:
46: public static void main(String[] args) {
47: Callable<Remote> task = new Callable<Remote>() {
48: public Remote call() throws Exception {
49: String url="rmi://localhost:2106/MyApp";
50: return (Remote) Naming.lookup(url);
51: }
52: };
53:
54: RetriableTask<Remote> r = new RetriableTask<Remote>(task);
55: try {
56: r.call();
57: }
58: catch (Exception e) {
59: e.printStackTrace();
60: }
61: }
62: }
//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();
Neat explanation, thanks!
ReplyDelete