Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Continue when a Future.failed(new Exception("")) is returned in Scala

Tags:

scala

How do I handle if a future returns a failed exception?

The scenario is that my code calls getValue(), maps the result to verifyValue() and then I want to be able to handle the case where the result of getValue() is Future.failed(new Exception("message")). However when I run this, if the result of getValue() is a failed future it just throws the exception rather than handling it.

Does anyone have any suggestions of how I would do this?

def method(): Future[JsObject] = {
    getValue().flatMap(verifyValue(_))
}

def getValue(): Future[JsObject] = {
    try {
        value1 <- getValue1()
        value2 <- getValue2(value1)
    } yield {
        value2
    }
}

def verifyValue(result: Any): Future[JsObject] = {
  result match {
    case e: Exception =>
      getValue()
    case json: JsObject => Future.successful(json)
  }
}

Update: I don't think I made this clear with the original question, but the reason why I flatmap the value is that I don't want to explicitly have to wait for any of the futures in my code, and therefore I don't want to use Future.onComplete{} to resolve the value.

Update 2: Another thing that might not be clear is that if it throws an exception, I want to call another method. I don't want it to just handle the exception, it is going to log the exception and then call another method whose return value is of the same type as getValue().

like image 264
annedroiid Avatar asked Oct 06 '16 05:10

annedroiid


2 Answers

Use recover or recoverWith

recover or recoverWith are called when future fails with an exception. In the recover block you can give the alternative value.

recoverWith unlike recover takes future of something

getValue().recover { case th =>
  //based on the exception type do something here
  defaultValue //returning some default value on failure
}
like image 108
pamu Avatar answered Sep 23 '22 17:09

pamu


What I ended up doing is using the Future.fallbackTo() method.

def method(): Future[JsObject] = {
    getValue().fallbackTo(method1()).fallbackTo(method2()).fallbackTo(method3())
}

If the future from the first getValue() fails, it will call method1(). If that also fails, it will call method2() etc. If one of the methods succeeds, it will return that value. If none of the methods succeed, it will return the failed future from getValue().

This solution isn't ideal, as I would preferably want to include all four of the exceptions thrown if all of the tries fail, but it at least allows me to retry the getValue() method.

like image 26
annedroiid Avatar answered Sep 22 '22 17:09

annedroiid