Is ExecutionContext.reportFailure working?


#1

While I was trying to stub out an execution context to test concurrent code, I noticed some surprising behavior demonstrated below. I would have expected the exception thrown by the Future to cause reportFailure to be invoked. To my surprise, reportFailure never got called at all, and the runnable.run() method carried on like nothing happened, even though an exception was thrown. Obviously the code block run by the future is being wrapped by a runnable at some point, the surprising thing is that it seems to be handling the exception in a way that never notifies the reportFailure method. I am having a hard time figuring it out from the source code, so was hoping someone more familiar with the scala.concurrent library could help me understand what is going on here. My eventual goal is to be able to unit-test concurrent code by having tests take control of when different futures are launched and resolved. That way I can resolve futures in different orders and make sure the code is correct no matter how the thread scheduler happens to fire off the futures.

import java.util.concurrent.TimeUnit

import org.scalatest.FunSuite

import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext, Future}

class PrototypeForStubbingExecutionContext extends FunSuite {
  test("foo") {
    implicit val executionContext = new ExecutionContext {
      override def execute(runnable: Runnable): Unit = {
        println("a")
        runnable.run()
        println("d")
      }

      override def reportFailure(cause: Throwable): Unit = {
        println("e")
        cause.printStackTrace()
        throw cause
      }
    }
    val x = Future {
      println("b")
      throw new RuntimeException("boo!")
      println("c")
    }(executionContext)
    Await.ready(x, Duration(1, TimeUnit.SECONDS))
    println(x)
  }
}

Output

a
b
d
Future(Failure(java.lang.RuntimeException: boo!))

#2

Hi, @SeanShubin. Have you found an answer to your question?