Skip to content


Things that are easier in Scala vol 1

Last week I ran into a cose where needed to add some logic to retry certain operations a number of times before failing. These operations can throw a variety of exceptions, some of which are recoverable, some of which are not. Due to a variety of issues the code in question must be Java. At least for the time being. So I set out to do this. The solution I came up with wasn’t bad as Java solutions go…

Step 1: identify recoverable exceptions. Because I control the code that can throw the exceptions this isn’t so bad. I create a simple RecoverableException class.

package org.mccv;
 
/**
 * A marker class for recoverable exceptions
 */
public class RecoverableException extends Exception{
 
}

Step 2: create an interface that defines a retryable operation.

package org.mccv;
 
/**
 * An interface that defines an execute operation to retry
 */
public interface Retryable<T> {
	public T execute() throws Exception;
}

Step 3: implement a class that will retry a retryable n times before failing.

package org.mccv;
 
/**
 * The implementation of our retrying class
 */
public class Retryer<T> {
	/**
	 * The retryable we will call
	 */
	private Retryable<T> retryable;
 
	/**
	 * Just assign our retryable field 
	 */
	public Retryer(Retryable<T> retryable){
		this.retryable = retryable;
	}
 
	/**
	 * Try to execute our retryable n times 
	 */
	public T tryTimes(int times) throws Exception{
		// store the last thrown recoverable exception
		RecoverableException lastException = null;
		// try the specified number of times
		for(int i = 0; i < times; i++){
			System.out.println("running it with " + (times-i) + " tries remaining");
			try{
				return retryable.execute();
			}catch(RecoverableException re){
				lastException = re;
			}
		}
		throw lastException;
	}
}

Step 4: implement the retryable interface with the operation we want retried

package org.mccv;
 
/**
 * An implementation of the Retryable interface
 */
public class RetryableImpl implements Retryable<String>{
	/**
	 * Show usage of the retryer
	 */
	public static void main(String [] args){
		// create a new retrier
		Retryer<String> retrier = new Retryer<String>(new RetryableImpl());
		// run the retrier 
		try{
			System.out.println("result = " + retrier.tryTimes(3));
		}catch(Exception e){
			System.out.println("failed after 3 tries");
		}
	}
 
	/**
	 * An intentionally flaky operation
	 */
	public String execute() throws Exception{
	    if(Math.random() > 0.3){
	        throw new RecoverableException();
	      }else{
	        return "foo";
	      }
 
	}
}

This works, and you can use anonymous inner classes to wrap stuff that doesn’t directly extend retryable. But it’s ugly. You have to make a lot of things final you wouldn’t otherwise (for instance let’s say you want your retryable to set a status code and response message. This gets difficult due to having to mark things final). It’s also a bit clumsy in that you have a Retryer class in play, plus an implementation of Retryable. What I really wanted was a way to say

retry(myOperation,nTimes).

With Scala I got a lot closer.

package org.mccv
 
/**
 * A marker trait indicating an exception that is recoverable.
 * Note that we could make this a trait as well.
 */
class RecoverableException extends Exception
 
/**
 * Usage of our retryable class
 */
object Retryer {
	/**
	* The workhorse.  Runs the operation, and if successful returns the result.
	* If unsuccessful calls itself recursively with a decremented run number.
	*/
	def tryNTimes[T](func: () => T, runNumber: Int):T = {
	  println("running it with " + runNumber + " tries remaining")
	  try{
		  func()
	  } catch {
	    case e:RecoverableException if runNumber > 1 => tryNTimes(func,runNumber - 1)
	    case e => throw e
	  }
	}
}
 
object Main {
   def main(args: Array[String]):Unit = {
    val tries = 3;
    try{
    	println(Retryer.tryNTimes[String](flakyMethod,tries))
     }catch{
       case e => println("failed after " + tries + " tries")
     }
  }
 
  def flakyMethod():String = {
    if(Math.random > 0.3){
      throw new RecoverableException()
    }else{
      "foo"
    }
  }
}

This is almost exactly what I’d like. I define a simple object that has a tryNTimes method. Because it’s an object it’s sort of like a Java static method… I can call Retryer.tryNTimes() directly. This is a recursive call. If a RecoverableException is caught, it just calls tryNTimes with the number of tries decremented. The beauty of this is that you can pass in any zero argument function. It doesn’t matter what class it’s defined in… it just has to know about recoverable exceptions.

I’ll be keeping an eye out for things that are easier in scala and keeping this series up to date. I’m sure I’ll be running into more of them.

Posted in scala.

  • khrabrov
    Wow! Just in time as I'm contemplating retrying slurping of a user's tweets. I'll add something like "requeue" as the final result where all N tries failed.
  • astubbs
    A couple of things..

    a) If you make it a trait - you can mix it in and just call tryNTimes without the object classifier - that's closer still, right?


    b) You can still retry and function, by creating a curried function or function pointer and passing that in:

    def myFunc(s:String) { println(s) }
    def toRetry = myFunc("Hi!")
    tryNTimes(toRetry, 5)

    right? I used this style in some test code I just wrote, where I had a test sequence that applied to several code blocks, some that took params.
blog comments powered by Disqus