2016-02-22 88 views
1

演員(OrgaActor)如何請求文檔的數據庫演員(DbActor)。 DbActor並不總是提供文檔,但也是一個數據庫錯誤異常。 OrgaActor現在應該使用詳細信息(它實際上是組織查詢,而不是通用數據庫查詢)來更改接收到的異常。我努力攔截來自DbActor的異常,並在發送給控制器的結果中更改它(OrgaCtl)。的OrgaActor在遊戲框架,以攔截和更改例外斯卡拉阿卡2.4.6

def receive = { 
    case GetDocument(id: String) => { 
     try { 
     val answer = (dbActor ? DbActor.GetDocument("Orga", id)).mapTo[JsValue] 
     play.Logger.debug("in answer") 
     answer.pipeTo(sender()) 
     } catch { 
     case e: Exception => 
      play.Logger.debug("in exception") 
      val fhe = error.FhException(e, 404, error.Error.ORGA_LOAD, "error on load " + id) 
      sender() ! akka.actor.Status.Failure(fhe)   
    } 
} 

非工作示例代碼DbActorGetDocument

case GetDocument(coll: String, id: String) => 
    try { 
    val response = new FigureheadDb().get(coll, id) 
    sender() ! response.jsonElementPayload() 
    } catch { 
    case e: Exception => 
     val fhe = error.FhException(e, 404, error.Error.FH_ID, "error on load " + id + " in coll " + coll) 
     sender() ! akka.actor.Status.Failure(fhe) 
     throw fhe 
    } 

從未顯示的inException調試消息,所以我想扔FHE代碼DbActor永遠不會到達呼叫OrgaActorDbActor被綁定到OrgaActorval dbActor = context.actorOf(Props [DbActor],name =「db-actor」)

問題是:如何攔截組織參與者中的數據庫參與者拋出的錯誤,並將強化的錯誤傳遞給全局錯誤處理程序?目前,全局錯誤處理程序總是獲取數據庫參與者錯誤。

case GetDocument(coll: String, id: String, originalSender: ActorRef) => 
    try { 
    val response = new FigureheadDb().get(coll, id) 
    sender() ! GetDocumentSuccess(response.jsonElementPayload(), originalSender) 
    } catch { 
    case e: Exception => 
     val fhe = error.FhException(e, 404, error.Error.FH_ID, "error on load " + id + " in coll " + coll) 
     sender() ! GetDocumentFailed(fhe, id, originalSender) 
    } 

OrgaActor

case GetDocument(id: String) => { 
    val answer : Future[Any] = dbActor ? DbActor.GetDocument(coll, id, sender()) 
    answer.map { 
     case success: DbActor.GetDocumentSuccess => 
     play.Logger.debug("in success") 
     success.originalSender ! success.result.as[JsValue] 
     case failure: DbActor.GetDocumentFailed => { 
     play.Logger.debug("in failure") 
     val fhe = error.FhException(failure.cause, 404, error.Error.ORGA_LOAD, "error on load " + failure.id) 
     failure.originalSender ! akka.actor.Status.Failure(fhe) 
     } 
     case any => { 
     play.Logger.error("Dead end") 
     } 
    } 
} 

對象DbActor:基於公認的答案

dbActor

case class GetDocument(coll: String, id: String, originalSender: ActorRef) 
    // http://stackoverflow.com/questions/35549414/how-to-intercept-and-change-exception-in-scala-akka-in-play-framework-2-4-6 
    sealed trait GetDocumentResult 
    case class GetDocumentSuccess(result: JsValue, originalSender: ActorRef) extends GetDocumentResult 
    case class GetDocumentFailed(cause: Exception, id: String, originalSender: ActorRef) extends GetDocumentResult 

回答

0

在您的OrgaActor中,您嘗試捕獲永遠不會拋出的exeption。

下面的代碼是從你的問題中引用的,但是我包含了一個answer的類型註釋。

try { 
    val answer: Future[JsValue] = (dbActor ? DbActor.GetDocument("Orga", id)).mapTo[JsValue] 
    play.Logger.debug("in answer") 
    answer.pipeTo(sender()) 
    } catch { ... } 

你可能會想到在第二行(val answer ....)拋出一個異常,但也不會拋出異常,但未來返回,這可能會成功或失敗。

使用​​未來的結果(可能是Status.Failure)被髮送到sender()。

作爲一個解決方案,您可以定義一個密封的特質GetDocumentResult這兩個案例類實現性狀:

// you already have this case class, I added the original sender, 
// since you might need this information to know where to send the final result 
case class GetDocument(coll: String, id: String, originalSender: ActorRef) 

sealed trait GetDocumentResult 
case class GetDocumentSuccess(result: JsValue, originalSender: ActorRef) extends GetDocumentResult 
case class GetDocumentFailed(cause: Exception, id: String, originalSender: ActorRef) extends GetDocumentResult 

使用這個你DbActor可以發送無論是GetDocumentSuccessGetDocumentFailed作爲對OrgaActor的響應。一旦OrgaActor收到響應,它可以將最終結果(成功或後處理失敗消息)發送給原始發件人。