如何使用akka.actor.Status.Failure捕获异常

时间:2019-01-25 14:35:02

标签: scala akka

我有一个负责MongoDB CRUD操作的演员,它可能抛出mongoException,我想在调用代码中捕获此异常,而我使用的是Ask模式,但是我仍然收到TimeOutException异常,但不是就我而言,我已经over this link

  

警告   要完成异常操作,您需要发送akka.actor.Status.Failure消息给发送者。当演员在处理消息时引发异常时,这不会自动完成。

我遵循了文档中给出的代码段

这是我的代码

class test extends Actor {

def receive () {

case GetRecordLists=>
try {  
 //some operations here 
   sender ! resultList
}
catch {
  mongoEX:MongoException=>
  log.error("got mongodb exception",mongoex)
  sender ! akka.actor.Status.Failure(mongoEx)
  throw mongoEx

e:Exception=>
  log.error("got exception",e)
  sender ! akka.actor.Status.Failure(e)
  throw e
}

}

}


class MainClass extends App {

try {
     val future: Future[scala.collection.mutable.Set[String]] = ask(test, GetRecordLists).mapTo[scala.collection.mutable.Set[String]]
     val results = Await.result(future, timeout.duration)
    }
    catch  {
      case e:Exception=>log.error("got the exception in main class ",e)
      throw new Exception(e)
    }
}

此处的预期行为是捕获MongoException 但是我得到

java.util.concurrent.TimeoutException: Futures timed out after [5 seconds]
    at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:219) ~[scala-library-2.11.1.jar:na]
    at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:223) ~[scala-library-2.11.1.jar:na]
    at scala.concurrent.Await$$anonfun$result$1.apply(package.scala:111) ~[scala-library-2.11.1.jar:na]
    at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53) ~[scala-library-2.11.1.jar:na]
    at scala.concurrent.Await$.result(package.scala:111) ~[scala-library-2.11.1.jar:na]
    at MainClass(MainClass.scala:118) [xyz_2.11.jar:0.1.0-SNAPSHOT]

1 个答案:

答案 0 :(得分:0)

您所做的看起来很正确。超时错误的唯一解释是,对mongo的操作尚未完成,并且5 seconds还不够。

请检查处理成功,失败和超时情况的非常简化的代码。

import akka.actor.{Actor, ActorSystem, Props}
import akka.actor.Status.Failure
import akka.util.Timeout
import akka.pattern.ask

import concurrent.duration._

class TestActor(body: () => String) extends Actor {
  override def receive: Receive = {
    case msg => try {
      sender() ! body()
    } catch {
      case ex: Throwable =>
        sender() ! Failure(ex)
    }
  }
}

object TestApp extends App {
  val system = ActorSystem("test")
  import system.dispatcher
  implicit val timeout: Timeout = 1.second
  val actorOk = system.actorOf(Props(new TestActor(() => "Hello")))
  val actorNok = system.actorOf(Props(new TestActor(() => sys.error("Boom"))))
  val actorTimeout = system.actorOf(Props(new TestActor(() => {Thread.sleep(3000); ""})))
  (actorOk ? "some message").mapTo[String].onComplete(println)
  (actorNok ? "some message").mapTo[String].onComplete(println)
  (actorTimeout ? "some message").mapTo[String].onComplete(println)
  Thread.sleep(2000)
  system.terminate()
}

打印

Success(Hello)
Failure(java.lang.RuntimeException: Boom)
Failure(akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://test/user/$c#-765807830]] after [1000 ms]. Message of type [java.lang.String]. A typical reason for `AskTimeoutException` is that the recipient actor didn't send a reply.)