Blog

Try is free in the Future

19 Jan, 2015

Lately I have seen a few developers consistently use a Try inside of a Future in order to make error handling easier. Here I will investigate if this has any merits or whether a Future on it’s own offers enough error handling.

If you look at the following code there is nothing that a Future can’t supply but a Try can:
[scala]
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Await, Future, Awaitable}
import scala.concurrent.duration._
import scala.util.{Try, Success, Failure}
object Main extends App {
// Happy Future
val happyFuture = Future {
42
}
// Bleak future
val bleakFuture = Future {
throw new Exception("Mass extinction!")
}
// We would want to wrap the result into a hypothetical http response
case class Response(code: Int, body: String)
// This is the handler we will use
def handle[T](future: Future[T]): Future[Response] = {
future.map {
case answer: Int => Response(200, answer.toString)
} recover {
case t: Throwable => Response(500, "Uh oh!")
}
}
{
val result = Await.result(handle(happyFuture), 1 second)
println(result)
}
{
val result = Await.result(handle(bleakFuture), 1 second)
println(result)
}
}
[/scala]
After giving it some thought the only situation where I could imagine Try being useful in conjunction with Future is when awaiting a Future but not wanting to deal with error situations yet. The times I would be awaiting a future are very few in practice though. But when needed something like this migth do:
[scala]
object TryAwait {
def result[T](awaitable: Awaitable[T], atMost: Duration): Try[T] = {
Try {
Await.result(awaitable, atMost)
}
}
}
[/scala]
If you do feel that using Trys inside of Futures adds value to your codebase please let me know.

guest
3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Julio
Julio
6 years ago

Thanks for the tip, helped here!

chad
chad
5 years ago

I’ve ended up using Future[Try[_]] quite often, and it’s almost always when I need to do Future.sequence on a collection of futures, and I don’t want the failure of one future to fail the entire thing.
So imagine I’m sending an HTTP request to 20 servers, and I want to enumerate their responses or errors. If one of them times out, I still want to save the results, so I end up with something like…
Future[List[Try[_]]
Usually the quickest way to accomplish this is just…
Future.sequence(futures.map(_.map(Success).recover(Failure(_)))
although maybe there’s some monad transformer approach that would be cleaner.

Explore related posts