Akka Future可以恢复什么?

时间:2014-07-28 16:06:50

标签: scala akka future

我很好奇在未来的recover函数可以恢复抛出异常的情况下?我一起使用Akka演员和未来:

这是我未来的电话:

implicit val timeout = Timeout(5.seconds) //yes, I already have this line.

val response = (ActorA ? someMessage(someStuff))
                    .mapTo[TransOk]
                    .map(message => (OK, message.get))
                    .recover{
                    case e => (BadRequest, e.getMessage)
                  }

我发送ActorA然后将结果映射到TransOK课程,最后我添加.recover{}

然后这是ActorA的方法:

case someMessage(stuff) =>
      //the exception being thrown here is not captured by Future.recover() method
      //why!?
      val id = if (some.canFind(stuff)) doSomething() 
               else throw new Exception("ERROR ERROR!")

      val result: Try[SomeDBType] = DAL.db.withSession { implicit session =>
        Try(DB.findStuff(stuff))
      }

      result match {
        case Success(content) => sender ! TransOk(content)
        case Failure(ex) => throw ex //let it escalate
      }

有趣的是:.recover()未捕获第一个异常。那么在什么情况下recover能够捕获异常?我认为它涵盖了被调用方法中发生的所有异常。

2 个答案:

答案 0 :(得分:4)

来自recover的{​​{1}}函数被设置为处理计算Future本身的值失败的情况。请考虑以下情况:

Future

在这种情况下,由于val f:Future[Int] = future{ val s:String = null s.length } 始终为空,因此String始终会失败。如果我们想要始终为此Future设置一个值而不管失败,我们会像Future一样使用{/ p>}:

recover

在这种情况下,如果我未来的计算失败,我总会有val finalFut = f.recover{case ex => 1} 包装值为1。

现在使用Future和Akka,我知道有两种方法会导致ask ask失败。第一个涉及超时发生。在这种情况下,你的Future肯定会开始。第二种情况涉及接收方将recover上游传播给发送方,如下所示:

Status.Failure

执行此操作将导致基于上游询问的未来以您想要的方式失败以及您的恢复启动。如果actor本身抛出未捕获的异常,则主管将重新启动它(通常),但该异常除非您通过def receive = { case _ => sender ! Status.Failure(new RuntimeException("foo")) }

明确指出,否则默认情况下不会从您的问题向上游传播到未来

答案 1 :(得分:0)

ActorA抛出异常,因此会将错误升级为其主管。你永远不会发送未来的回复来处理。你可以尝试设置一个更短的超时,看看你得到了什么。

此示例scala脚本将立即显示错误,但在5秒后显示错误消息,说明您有超时而不是其他错误:

import akka.actor.{Actor,ActorSystem,Props}
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

class ActorA() extends Actor {
  def receive = {
    case "message" => throw new Exception("oops")
  }
}

implicit val timeout = Timeout(5.seconds)

val sys = ActorSystem("sys")
val a = sys.actorOf(Props(new ActorA()))

(a ? "message").recover { case e => "bad things happened: " + e }  foreach (println)