Reputation: 11522
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
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