How to transform failed future exceptions in Scala?
Asked Answered
N

1

6

I have always used recover to transform exceptions in failed futures similar to

def selectFromDatabase(id: Long): Future[Entity] = ???

val entity = selectFromDatabase(id) recover {   
  case e: DatabaseException =>
    logger.error("Failed ...", e)
    throw new BusinessException("Failed ...", e) 
}

This code snippet transforms a DatabaseException into a BusinessException. However, from a comment in the question: Scala recover or recoverWith

... generally speaking the point of "recover" and "recoverWith" is not to simply transform your exceptions from one type to another, but to recover from the failure by performing the task in a different way so that you no longer have a failure.

So apparently I am not supposed to use recover to transform exceptions. What is the correct way to transform Future exceptions / failed Future?

Neckband answered 29/11, 2019 at 5:1 Comment(1)
If you need to transform a Failure to another Failure, recover (or slightly better recoverWith { .... Future.failed(new BusinessException to avoid the throw) is fine.Wed
M
4

Since you are simply transforming an exception to another exception, I think using recover is ok. Use recoverWith when you want to try a different strategy for solving the problem, that is, when you hope to get a successful result back. For example consider the following use of recoverWith

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

object futureRecoverWith extends App {

  case class Entity(id: Int, name: String)

  def selectFromDatabaseById(id: Int): Future[Entity] = Future(throw new RuntimeException("Boom"))
  def selectFromDatabaseByName(name: String): Future[Entity] = Future(Entity(42, "picard"))

  val entity =
    selectFromDatabaseById(42) recoverWith {
      case error =>
        println("Failed to get Entity by ID. Trying by name...")
        selectFromDatabaseByName("picard")
    }

  entity.map(println)
}

which outputs

Failed to get Entity by ID. Trying by name...
Entity(42,picard)

Note how we attempted to first get the entity by id, and then failing that, we attempted by name.

Misinterpret answered 29/11, 2019 at 10:0 Comment(1)
What about using transform to avoid throwing the exception but rather returning a new Failed (the downside is doing an identity on the Success).Empedocles

© 2022 - 2024 — McMap. All rights reserved.