I implemented a simple job processor that processes subjobs within futures (scala.actors.Futures). These futures themselves can create more futures for processing subjobs. Now, if one of these subjobs throws an exception, i want the job processor to reply with an error message for that job. I have a workaround solution for discovering failed subjobs, but i'm not sure if that's the best solution. Basically it works like this:

sealed trait JobResult
case class SuccessResult(content: String) extends JobResult
case class FailedResult(message: String) extends JobResult

for(subjob <- subjobs) yield {
  future {
    try {
    } catch {
      case e:Exception => FailedResult(e.getMessage)                              

The result at the top level is a recursive List of Lists of Lists... of JobResults. I recursively search the List for a failed Result and then return an error or the combined result depending on the types of results. That works but i'm wondering if there's is a more elegant/easier solution for dealing with exceptions in futures?


The way you do it now, is essentially what scala.Either was designed for. See http://www.scala-lang.org/api/current/scala/Either.html

  • Yep, use Either, or even better, Validation from scalaz. – Jesper Nordenberg Apr 20 '11 at 9:11
  • Thx, will have a look at both suggestions :) – rocksteady Apr 21 '11 at 13:16

Modern scala futures are like Either in that they contain either a successful result or a Throwable. If you re-visit this code in scala 2.10, i think you'll find the situation quite pleasant.

Specifically, scala.concurrent.Future[T] technically only "is-a" Awaitable[T], but _.onComplete and Await.ready(_, timeout).value.get both present its result as a scala.util.Try[T], which is a lot like Either[Throwable, T] in that it's either the result or an exception.

Oddly, _.transform takes two mapping functions, one for T => U and one for Throwable => Throwable and (unless i'm missing something) there's no transformer that maps the future as Try[T] => Try[U]. Future's .map will allow you to turn a success into a failure by simply throwing an exception in the mapping function, but it only uses that for successes of the original Future. Its .recover, similarly can turn a failure into a success. If you wanted to be able to change successes to failures and vice-versa, you'd need to build something yourself that was a combination of _.map and _.recover or else use _.onComplete to chain to a new scala.concurrent.Promise[U] like so:

import scala.util.{Try, Success, Failure}
import scala.concurrent.{Future, Promise}
import scala.concurrent.ExecutionContext

def flexibleTransform[T,U](fut: Future[T])(f: Try[T] => Try[U])(implicit ec: ExecutionContext): Future[U] = {
  val p = Promise[U]
  fut.onComplete { res =>
    val transformed = f(res)

which would be used like so:

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration.Duration.Inf

def doIt() {
  val a: Future[Integer] = Future {
    val r = scala.util.Random.nextInt
    if (r % 2 == 0) {
      throw new Exception("we don't like even numbers")
    } else if (r % 3 == 0) {
      throw new Exception("we don't like multiples of three")
    } else {

  val b: Future[String] = flexibleTransform(a) {
    case Success(i) =>
      if (i < 0) {
        // turn negative successes into failures
        Failure(new Exception("we don't like negative numbers"))
      } else {
    case Failure(ex) =>
      if (ex.getMessage.contains("three")) {
        // nevermind about multiples of three being a problem; just make them all a word.
      } else {

  val msg = try {
    "success: " + Await.result(b, Inf)
  } catch {
    case t: Throwable =>
      "failure: " + t

for { _ <- 1 to 10 } doIt()

which would give something like this:

failure: java.lang.Exception: we don't like even numbers
failure: java.lang.Exception: we don't like negative numbers
failure: java.lang.Exception: we don't like negative numbers
success: three
success: 1756800103
failure: java.lang.Exception: we don't like even numbers
success: 1869926843
success: three
failure: java.lang.Exception: we don't like even numbers
success: three

(or you could "pimp" Future into a RichFutureWithFlexibleTransform with an implicit def and make flexibleTransform a member function of that, dropping the fut param and simply using this)

(even better would be to take Try[T] => Future[U] and call it flexibleFlatMap so you could do async things in the transform)

  • 1
    You may want to mention the type: Try – bluenote10 May 1 '14 at 15:27

Your Answer

