Question

Any idea why the code below can handle the Success without any issues, but when trying to return a Failure ends up throwing an Exception?

Exception in thread "main" au.com.ingdirect.splunk.Implicits.package$LameExcuse: hello at au.com.ingdirect.splunk.Implicits.package$RichJob$$anonfun$asFuture$1.apply(package.scala:42) at au.com.ingdirect.splunk.Implicits.package$RichJob$$anonfun$asFuture$1.apply(package.scala:36) at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)

This is my code:

/* --- Main.scala --- */
import test.Implicits._
val job = service.createJob("search immediatePayment", queryArgs)
Await.result(job, 10 seconds)

job.onComplete{
    case Success(j) => println("Success!!")
    case Failure(l: LameExcuse) => println("Why I never fall here?") 
}

/* --- package.scala ---*/
package object Implicits {
implicit val executorService = Executors.newFixedThreadPool(4)
implicit val executionContext = ExecutionContext.fromExecutorService(executorService)

case class LameExcuse(msg: String) extends Exception(msg)

implicit class RichJob(val job: Job) {
  def asFuture(): Future[Job] = {
    // I promise i will return a completed Job
    val p = Promise[Job]()
    val fail = false
    // ... and here i am
    future {       
        while (!job.isDone()) {
          Thread.sleep(1000)
        }
        if (fail)
          p failure (new LameExcuse("Service unavailable")) //<-- This will print the stacktrace on the console, but it will not send a Failure
        else
          p success job //<-- This works fine
    } 
    p.future

  }
}

Thanks

Was it helpful?

Solution

I think part of your issue is that in Main.scala, you are first performing a blocking Await.result before you register your non-blocking onComplete callback. With Await.result, if the Future is failed, whatever exception the Failure is wrapping will be thrown all the way out. So, in your case, if the Future is failed, you will never get to the code where you register the onComplete callback. If you remove the Await.result, things should work as expected for you, more gracefully failing and hitting your Failure case in the onComplete callback.

In addition, in asFuture, I'm not sure why you need that Promise. You already created a Future and can just return that as opposed to using a Promise. Your code could be simplified to:

def asFuture(): Future[Job] = {
  val fail = false
  future {       
      while (!job.isDone()) {
        Thread.sleep(1000)
      }
      if (fail)
        throw new LameExcuse("Service unavailable")          
      job
  } 
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top