我很好奇在未来的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
能够捕获异常?我认为它涵盖了被调用方法中发生的所有异常。
答案 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)