es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Fallo en la solicitud de un actor escrito en lugar de envolverlo con Try.

import akka.actor.typed.scaladsl.AskPattern._
object MyActor {
sealed trait Command
case class MyCommand(replyTo: ActorRef[Try[String]]) extends Command

def apply(): Behaviors.Receive[Command] = {
val failureMessage = util.Failure(new RuntimeException(“Timeout”))
Behaviors.receiveMessage {
case MyCommand(replyTo) => replyTo ! failureMessage
Behaviors.same
}
}
}

val worker = testKit.spawn(MyActor())

// Act
val res = worker.ask[Try[String]](me => MyActor.MyCommand(replyTo = me))

// Assert
println(Await.result(res, Duration.Inf)) // Return Failure(java.lang.RuntimeException: Timeout)
// But i want to do:
intercept[RuntimeException] {
Await.result(res, Duration.Inf)
}
// and on success i want to return instead of Success[T] as T

Notice that I'm wrapping the result with `Try` in order to return `Success` or `Failure`. The problem is that I don't want to do it, i want to fail the whole `Future` on the `ask` requests.

Is it possible to do it?
Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, es posible que todo el Future falle en las solicitudes ask sin envolverlo con Try. Esto se puede lograr utilizando el método mapError proporcionado por la API de Future. El método mapError permite mapear un fallo de un Future a un tipo de error diferente.

    En este escenario, podemos utilizar mapError para lanzar una excepción en lugar de envolver el resultado en Failure. El código se vería así:

    import akka.actor.typed.scaladsl.AskPattern._
    
    object MyActor {
      sealed trait Command
      case class MyCommand(replyTo: ActorRef[String]) extends Command
    
      def apply(): Behaviors.Receive[Command] = {
        Behaviors.receiveMessage {
          case MyCommand(replyTo) => replyTo ! "Success"
                                  Behaviors.same
        }
      }
    }
    
    val worker = testKit.spawn(MyActor())
    
    // Act
    val res = worker.ask[String](me => MyActor.MyCommand(replyTo = me)).mapError {
      case e: RuntimeException => e
      case _ => new RuntimeException("Error desconocido")
    }
    
    // Assert
    intercept[RuntimeException] {
      Await.result(res, Duration.Inf)
    } // Lanzará RuntimeException("Timeout") si el actor worker respondió con un mensaje de fallo, de lo contrario devuelve el resultado real ("Success") como un String
    

    Nota que hemos eliminado el envoltorio Try en el parámetro replyTo y cambiamos el tipo de resultado de worker.ask a String. También utilizamos mapError para lanzar una RuntimeException en lugar de envolver el resultado en Failure. Finalmente, envolvimos nuestra afirmación con intercept[RuntimeException] para capturar cualquier RuntimeException y fallar la prueba si ocurre.

Comments are closed.