com.healthmarketscience.rmiio
Class RemoteRetry

java.lang.Object
  extended by com.healthmarketscience.rmiio.RemoteRetry
Direct Known Subclasses:
RemoteRetry.Always, RemoteRetry.Never, RemoteRetry.Simple

public abstract class RemoteRetry
extends Object

Utility class for automatically retrying remote method calls (which might fail for spurious reasons). Pretty much any remote method call should deal with RemoteExceptions because many transient failures (such as temporary network connection failures) can cause these exceptions, and the call may succeed when reattempted.

The major caveat for this class is the remote method call must be idempotent. This means, in essence, that repeated calls with the same arguments should generate the exact same results. An example of a non-idempotent call would be "remove $10 from my bank account". If this call were sent twice (because the first attempt seemed to fail), you could end up with $20 removed from your bank account. In order to solve this, you could add a unique sequence id to the call, "remove $10 from my bank account, seqId(5)", and the server could ignore the second call (assuming it was keeping track of the sequence ids that it had processed thus far). In other words, remote method calls are a lot harder to make than local method calls and much care should be taken when dealing with remote APIs.

Although RemoteRetry is an abstract class, there are a variety of simple implementations, as well as static instances of these implementations. See the implementations for more details.

Example usage:


 // use simple retry mechanism
 RemoteRetry retry = RemoteRetry.SIMPLE;

 // since we are using anonymous inner classes, these must be final
 final MyRemoteObject myRemoteObject;
 final int myArgument;

 // make a call with a return value
 Result res = retry.call(new RemoteRetry.Caller<Result>()
   {
     public Result call() throws RemoteException, MyException {
       return myRemoteObject.getResult(myArgument);
     }
   }, LOG, MyException.class, RemoteException.class);

 // make a call with no return value (use VoidCaller)
 retry.call(new RemoteRetry.VoidCaller()
   {
     public void call() throws RemoteException, MyException {
       return myRemoteObject.setValue(myArgument);
     }
   }, LOG, MyException.class, RemoteException.class);

Note that the various call() methods use generics to create methods with custom Exception signatures in addition to the custom return types.

Author:
James Ahlborn

Nested Class Summary
static class RemoteRetry.Always
          Simple implementation of RemoteRetry which always retries RemoteExceptions thrown from the remote method call.
static class RemoteRetry.Caller<RetType>
          Utility type implemented by those atttempting to make remote method calls using this retry mechanism.
static class RemoteRetry.Never
          Simple implementation of RemoteRetry which never retries.
static class RemoteRetry.Simple
          Simple implementation of RemoteRetry which retries RemoteExceptions some number of times and uses the backoff strategy from simpleBackOff(int, org.apache.commons.logging.Log).
static class RemoteRetry.SimpleAlways
          Simple implementation of Always retry strategy which uses the backoff strategy from simpleBackOff(int, org.apache.commons.logging.Log).
static class RemoteRetry.VoidCaller
          Simple subclass of Caller for use by remote method calls which do not need to return values.
 
Field Summary
protected static org.apache.commons.logging.Log LOG
           
static RemoteRetry NEVER
          instance of the RemoteRetry.Never retry strategy for general use.
protected static Class<RuntimeException> RUNTIME_CLASS
          RuntimeException class for overloading of exception types
static RemoteRetry SIMPLE
          instance of the RemoteRetry.Simple retry strategy for general use.
static RemoteRetry.Always SIMPLE_ALWAYS
          instance of the RemoteRetry.SimpleAlways retry strategy for general use.
 
Constructor Summary
protected RemoteRetry()
           
 
Method Summary
abstract  void backOff(int numRetries, org.apache.commons.logging.Log log)
          Should delay for some implementation defined amount of time (to give the callee, network, etc.
<RetType> RetType
call(RemoteRetry.Caller<RetType> caller)
          Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which only throws RuntimeException.
<RetType,ExType1 extends Throwable>
RetType
call(RemoteRetry.Caller<RetType> caller, Class<ExType1> throwType1)
          Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and one user defined Exception.
<RetType,ExType1 extends Throwable,ExType2 extends Throwable>
RetType
call(RemoteRetry.Caller<RetType> caller, Class<ExType1> throwType1, Class<ExType2> throwType2)
          Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and two user defined Exceptions.
<RetType,ExType1 extends Throwable,ExType2 extends Throwable,ExType3 extends Throwable>
RetType
call(RemoteRetry.Caller<RetType> caller, Class<ExType1> throwType1, Class<ExType2> throwType2, Class<ExType3> throwType3)
          Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and three user defined Exceptions.
<RetType> RetType
call(RemoteRetry.Caller<RetType> caller, org.apache.commons.logging.Log log)
          Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which only throws RuntimeException.
<RetType,ExType1 extends Throwable>
RetType
call(RemoteRetry.Caller<RetType> caller, org.apache.commons.logging.Log log, Class<ExType1> throwType1)
          Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and one user defined Exception.
<RetType,ExType1 extends Throwable,ExType2 extends Throwable>
RetType
call(RemoteRetry.Caller<RetType> caller, org.apache.commons.logging.Log log, Class<ExType1> throwType1, Class<ExType2> throwType2)
          Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and two user defined Exceptions.
<RetType,ExType1 extends Throwable,ExType2 extends Throwable,ExType3 extends Throwable>
RetType
call(RemoteRetry.Caller<RetType> caller, org.apache.commons.logging.Log log, Class<ExType1> throwType1, Class<ExType2> throwType2, Class<ExType3> throwType3)
          Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and three user defined Exceptions.
protected
<RetType> RetType
callImpl(RemoteRetry.Caller<RetType> caller, org.apache.commons.logging.Log log)
          Implementation of the actual retry logic.
abstract  boolean shouldRetry(Throwable t, int numRetries)
          Returns true if the caller should attempt to repeat the current remote method call given the number of previous reattempts.
protected static void simpleBackOff(int numRetries, org.apache.commons.logging.Log log)
          Implementation of a simple backoff strategy: First retry returns immediately Retries 1 - 30 wait that many seconds each time before returning (after 1st retry wait 1 second, after 2nd retry wait 2 seconds...) Retries > 30 wait 30 seconds each time before returning
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

LOG

protected static final org.apache.commons.logging.Log LOG

RUNTIME_CLASS

protected static final Class<RuntimeException> RUNTIME_CLASS
RuntimeException class for overloading of exception types


NEVER

public static final RemoteRetry NEVER
instance of the RemoteRetry.Never retry strategy for general use.


SIMPLE

public static final RemoteRetry SIMPLE
instance of the RemoteRetry.Simple retry strategy for general use.


SIMPLE_ALWAYS

public static final RemoteRetry.Always SIMPLE_ALWAYS
instance of the RemoteRetry.SimpleAlways retry strategy for general use.

Constructor Detail

RemoteRetry

protected RemoteRetry()
Method Detail

simpleBackOff

protected static void simpleBackOff(int numRetries,
                                    org.apache.commons.logging.Log log)
Implementation of a simple backoff strategy:
  1. First retry returns immediately
  2. Retries 1 - 30 wait that many seconds each time before returning (after 1st retry wait 1 second, after 2nd retry wait 2 seconds...)
  3. Retries > 30 wait 30 seconds each time before returning

Parameters:
numRetries - number of retries which have happended thus far
log - debug log

callImpl

protected final <RetType> RetType callImpl(RemoteRetry.Caller<RetType> caller,
                                           org.apache.commons.logging.Log log)
                          throws Throwable
Implementation of the actual retry logic. Calls the call() method of the given Caller, returning results. All Throwables will be caught and shouldRetry() will be queried to see if the call should be reattempted. Iff shouldRetry() returns true, backoff() is called in order to allow the other end of the connection to have a breather and then the call() is reattempted (and the cycle repeats). Otherwise, the original Throwable is thrown to the caller.

Parameters:
caller - implementation of the actual remote method call
Throws:
Throwable

call

public <RetType> RetType call(RemoteRetry.Caller<RetType> caller)
Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which only throws RuntimeException.


call

public <RetType> RetType call(RemoteRetry.Caller<RetType> caller,
                              org.apache.commons.logging.Log log)
Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which only throws RuntimeException.


call

public <RetType,ExType1 extends Throwable> RetType call(RemoteRetry.Caller<RetType> caller,
                                                        Class<ExType1> throwType1)
             throws ExType1 extends Throwable
Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and one user defined Exception.

Throws:
ExType1 extends Throwable

call

public <RetType,ExType1 extends Throwable> RetType call(RemoteRetry.Caller<RetType> caller,
                                                        org.apache.commons.logging.Log log,
                                                        Class<ExType1> throwType1)
             throws ExType1 extends Throwable
Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and one user defined Exception.

Throws:
ExType1 extends Throwable

call

public <RetType,ExType1 extends Throwable,ExType2 extends Throwable> RetType call(RemoteRetry.Caller<RetType> caller,
                                                                                  Class<ExType1> throwType1,
                                                                                  Class<ExType2> throwType2)
             throws ExType1 extends Throwable,
                    ExType2 extends Throwable
Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and two user defined Exceptions.

Throws:
ExType1 extends Throwable

call

public <RetType,ExType1 extends Throwable,ExType2 extends Throwable> RetType call(RemoteRetry.Caller<RetType> caller,
                                                                                  org.apache.commons.logging.Log log,
                                                                                  Class<ExType1> throwType1,
                                                                                  Class<ExType2> throwType2)
             throws ExType1 extends Throwable,
                    ExType2 extends Throwable
Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and two user defined Exceptions.

Throws:
ExType1 extends Throwable

call

public <RetType,ExType1 extends Throwable,ExType2 extends Throwable,ExType3 extends Throwable> RetType call(RemoteRetry.Caller<RetType> caller,
                                                                                                            Class<ExType1> throwType1,
                                                                                                            Class<ExType2> throwType2,
                                                                                                            Class<ExType3> throwType3)
             throws ExType1 extends Throwable,
                    ExType2 extends Throwable,
                    ExType3 extends Throwable
Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and three user defined Exceptions.

Throws:
ExType1 extends Throwable

call

public <RetType,ExType1 extends Throwable,ExType2 extends Throwable,ExType3 extends Throwable> RetType call(RemoteRetry.Caller<RetType> caller,
                                                                                                            org.apache.commons.logging.Log log,
                                                                                                            Class<ExType1> throwType1,
                                                                                                            Class<ExType2> throwType2,
                                                                                                            Class<ExType3> throwType3)
             throws ExType1 extends Throwable,
                    ExType2 extends Throwable,
                    ExType3 extends Throwable
Wrapper for callImpl(com.healthmarketscience.rmiio.RemoteRetry.Caller, org.apache.commons.logging.Log) which throws RuntimeException and three user defined Exceptions.

Throws:
ExType1 extends Throwable

shouldRetry

public abstract boolean shouldRetry(Throwable t,
                                    int numRetries)
Returns true if the caller should attempt to repeat the current remote method call given the number of previous reattempts.

Parameters:
t - throwable thrown
numRetries - number of previous reattempts
Returns:
true iff call should be repeated, true otherwise

backOff

public abstract void backOff(int numRetries,
                             org.apache.commons.logging.Log log)
Should delay for some implementation defined amount of time (to give the callee, network, etc. time to recover) given the number of previous reattempts. Will be called iff shouldRetry() returned true. Good implementations should implement some sort of increased delay based on the number of reattempts.

Parameters:
numRetries - number of previous reattempts
log - debug log


Copyright © 2006–2016 Health Market Science. All rights reserved.