2013-07-22 15 views
8

ここでDbActorがスローした例外をどのように処理すればよいですか?私はそれを処理する方法がわからない、失敗のケースをパイプする必要がありますか?質問パターンと監督で例外を処理する方法

class RestActor extends Actor with ActorLogging { 
    import context.dispatcher 

    val dbActor = context.actorOf(Props[DbActor]) 
    implicit val timeout = Timeout(10 seconds) 


    override val supervisorStrategy: SupervisorStrategy = { 
    OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) { 
     case x: Exception => ??? 
    } 
    } 

    def receive = { 
    case GetRequest(reqCtx, id) => { 

     // perform db ask 
     ask(dbActor, ReadCommand(reqCtx, id)).mapTo[SomeObject] onComplete { 
     case Success(obj) => { // some stuff } 
     case Failure(err) => err match { 
      case x: Exception => ??? 
     } 
     } 
    } 
    } 
} 

事前に感謝の気持ちになるでしょうか。

答えて

6

私はあなたのコードサンプルで質問をもとに、ここで見ることができる質問のカップルがあります。

  1. 私はの定義におけるデフォルトのスーパーバイザーの動作を無効にするとき、私はどのようなものの種類を行うことができますが、例外を処理する方法は?

  2. askを使用して、私は私が待っていますFutureFailure結果を得るとき、私は物事の種類を行うことができますか?

まず最初の質問(通常は良いアイデア)で始まるのをしてみましょう。デフォルトのスーパバイザ戦略をオーバーライドすると、その子アクターで処理されなかった例外の種類を、その失敗した子アクターとの対処に関してどのように処理するかを変更することができます。前の文のキーワードはunhandledです。リクエスト/レスポンスを行っているアクターにとって、実際には、特定の例外を処理(捕捉)して、特定のレスポンスタイプを返す(または上流の未来に失敗する、後でもっと失敗する)ことがあります。未処理の例外が発生した場合、基本的には送信者に問題の説明を返すことができなくなり、Futureが完了しないため、送信者はおそらくTimeoutExceptionになります。あなたが明示的に扱うものを理解したら、カスタムスーパーバイザ戦略を定義する際に、他のすべての例外を考慮することができます。ここでは、このブロック内:

OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) { 
    case x: Exception => ??? 
} 

あなたは障害が監督の立場からどのように処理するかを定義し、障害Directiveに例外タイプをマップするチャンスを得ます。オプションは次のとおりです。

  1. ストップ - 完全子役を停止し、それに任意の複数のメッセージを送信しない

  2. 再開 - 失敗した子を再開し、

  3. 現在の内部状態を維持するためにそれを再起動しません
  4. 再起動 - 同様に再開するが、この場合には、古いインスタンスは破棄され、新しいインスタンスが作成され、内部状態がリセットされる(事前開始)

  5. エスカレート - アップエスカレート今

    OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 10 seconds) { 
        case x: SQLException => Resume 
        case other => Restart 
    } 
    

    :スーパーバイザ

の親への連鎖は、それではSQLException与えられたあなたが再開したいとあなたはあなたのコードは次のようになり、再起動したい他のすべて与えられたとしましょうFutureFailure応答を返すときに何をすべきかに関する第2の質問については、この場合、それはその結果として起こるはずだったものに依存していると思います。Future残りの俳優自体がHTTP要求を完了するための責任があったなら、あなたはこのような何かを行うことができ、(のはhttpCtxは、その上にcomplete(statusCode:Int, message:String)機能を持っているとしましょう):

別の俳優が上流の完了を担当した今ならば
ask(dbActor, ReadCommand(reqCtx, id)).mapTo[SomeObject] onComplete { 
    case Success(obj) => reqCtx.complete(200, "All good!") 
    case Failure(err:TimeoutException) => reqCtx.complete(500, "Request timed out") 
    case Failure(ex) => reqCtx.complete(500, ex.getMessage) 
    } 

HTTP要求し、その俳優に対応するために必要な、あなたはこのような何かを行うことができます:

val origin = sender 
    ask(dbActor, ReadCommand(reqCtx, id)).mapTo[SomeObject] onComplete { 
    case Success(obj) => origin ! someResponseObject 
    case Failure(ex) => origin ! Status.Failure(ex) 
    } 

このアプローチは成功ブロックにあなたが最初に応答する前に、結果オブジェクトをマッサージすることを前提としています。あなたがそれを行うにはしたくないし、あなたが送信者に取り扱い、結果を延期したい場合は、あなただけ行うことができます。一つは、エラーのすべてをキャッチして転送することもできますシンプルなシステムについては

val origin = sender 
    val fut = ask(dbActor, ReadCommand(reqCtx, id)) 
    fut pipeTo origin 
+0

私はそれを得ると思う、実際の鍵は未処理のものを理解することです – graph1ZzLle

3

質問と監督を結びつける良い例を示すアクティベーター(http://www.typesafe.com/activator)テンプレートがあります:http://www.typesafe.com/activator/template/akka-supervision

+0

ありがとう、私はこれをチェックします – graph1ZzLle

+0

btw:その例の要点は、親アクターが送信者とワーカーアクターのマップを保持することです( 'Map [A​​ctorRef、ActorRef]')。子の例外が発生した場合の監視戦略。 – rethab

0

を。そのために私は監督で悩まずに受け取る方法、ラップするために、この小さな関数を作った:

import akka.actor.Actor.Receive 
    import akka.actor.ActorContext 
    /** 
    * Meant for wrapping the receive method with try/catch. 
    * A failed try will result in a reply to sender with the exception. 
    * @example 
    *   def receive:Receive = honestly { 
    *   case msg => sender ! riskyCalculation(msg) 
    *   } 
    *   ... 
    *   (honestActor ? "some message") onComplete { 
    *   case e:Throwable => ...process error 
    *   case r:_ => ...process result 
    *   } 
    * @param receive 
    * @return Actor.Receive 
    * 
    * @author Bijou Trouvaille 
    */ 
    def honestly(receive: =>Receive)(implicit context: ActorContext):Receive = { case msg => 
     try receive(msg) catch { case error:Throwable => context.sender ! error } 
    } 

を、あなたは、パッケージファイルにそれを置き、akka.pattern.pipeラなどをインポートすることができます。明らかに、これは非同期コードによってスローされる例外を処理しません。