Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interrupt Future map chain and return a Left

How can I return a Left in the middle of a future map chain and then fail the future? I am sending an example to clarify.

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

object TestApp extends App {

  final case class Message(statusCode: Int, data: String)
  final case class Success(data: String)
  final case class Failure()

  val msg = Message(500, "My data")
  val future = Future { msg }

  def getMessage(future: Future[Message]): Future[Either[Failure, Success]] = {
    future.map { msg =>
      // Evaluate msg here - if failure, make this feature fail and then return Left(Failure), otherwise, continue in the chain
      msg
    }.map(_.data).map(data => Right(Success(data)))
  }
}
like image 489
Andre Fagundes Avatar asked Feb 15 '26 17:02

Andre Fagundes


1 Answers

One option is to throw an exception which will fail the Future and then recover to a Left like so

  def getMessage(future: Future[Message]): Future[Either[Failure, Success]] =
    future
      .map(msg => if (msg.statusCode == 500) throw new RuntimeException("boom") else msg)
      .map(_.data)
      .map(data => Right(Success(data)))
      .recover{case ex => Left(Failure())}

Another option is to transform like so

  def getMessage(future: Future[Message]): Future[Either[Failure, Success]] = {
    future
      .map(msg => if (msg.statusCode == 500) throw new RuntimeException("boom") else msg)
      .map(_.data)
      .transform(v => scala.util.Success {
        v.toEither
          .map(v => Success(v))
          .left.map(e => Failure())
      })
  }

Warning, you have defined your own Success/Failure which shadows Scala's Success/Failure.

like image 158
Mario Galic Avatar answered Feb 18 '26 07:02

Mario Galic