Greg
Greg

Reputation: 11522

How can I safely do retries on a Scala Future?

I have some code that initiates a "slow" process, which I wrap in a Future. If something goes wrong, I want to slowly loop and retry after a pause--indefinitely. Kinda like this: (I know that eventually a human will intervene and fix the problem)

  def doSomething():Unit = {
    aFutureThing().onComplete { 
      case Success(s) => println("Success: "+s)
      case Failure(x) =>
        // Take some (hopefully) corrective action here, call for help, etc.
        Thread.sleep(1000) // pause a bit
        doSomething() // and try again...
    }
  }
  doit()

When the onComplete callback is called, is doSomething() still on the stack or has it been popped because we've returned while the Future was executing the slow task (aFutureThing)? Will this recursive calling of doSomething (eventually) blow up the stack/OutOfMemory or something? If so... is there a safer way to do retries on a Future?

Upvotes: 4

Views: 5911

Answers (1)

Dima
Dima

Reputation: 40510

There is no recursion here. doSomething will create Future and return immediately, while the Future is submitted for execution on another thread (it might actually get executed on the same thread, if it is part of the pool, but not before doSomething returns.

You could see this for yourself by running something like this in repl:

def foo(n: Int): Future[Int] = Future {
   Thread.sleep(1000)
   if(n < 10) throw new IllegalArgumentException(); else n 
} recoverWith { case e => 
   e.printStackTrace();
   println("N was " + n)
   Thread.sleep(1000)
   println("Rinse and repeat!")
   foo(n+1)
}

foo(1)

It will "retry" 9 times before actually succeeding, and print the stack of the exception every time, so you can see that the tracebacks are identical, they do not grow, because there is no recursion.

Upvotes: 5

Related Questions