9

ここで DbActor によってスローされた例外をどのように処理すればよいですか? 処理方法がわかりません。Failure ケースをパイプする必要がありますか?

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 => ???
        }
      }
    }
  }
}

ご意見をお待ちしております。よろしくお願いします。

4

2 に答える 2

7

コードサンプルの質問に基づいて、ここで確認できる質問がいくつかあります。

  1. 例外の処理方法の定義でデフォルトのスーパーバイザーの動作をオーバーライドすると、どのようなことができますか?

  2. を使用している場合、 で結果を待っているaskときに、どのようなことができますか?FailureFuture

最初の質問から始めましょう (通常は良い考えです)。デフォルトのスーパバイザ ストラテジをオーバーライドすると、失敗した子アクターをどう処理するかに関して、子アクターの特定の種類の未処理の例外の処理方法を変更できるようになります。その前の文のキーワードは ですunhandled。要求/応答を行っているアクターの場合、実際には特定の例外を処理 (キャッチ) し、代わりに特定の応答タイプを返したい場合があります (または、上流の将来を失敗させます。これについては後で詳しく説明します)。未処理の例外が発生すると、基本的に送信者に問題の説明を返信することができなくなり、送信者はおそらくTimeoutException代わりにFuture完成することはありません。何を明示的に処理するかを理解したら、カスタム スーパーバイザー戦略を定義するときに、残りのすべての例外を考慮することができます。このブロック内:

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

例外タイプを障害にマップする機会が得られますDirective。これは、監視の観点から障害がどのように処理されるかを定義します。オプションは次のとおりです。

  1. 停止 - 子アクターを完全に停止し、これ以上メッセージを送信しません

  2. 再開 - 失敗した子を再開し、再起動せずに現在の内部状態を維持します

  3. 再起動 - 再開に似ていますが、この場合、古いインスタンスが破棄され、新しいインスタンスが構築され、内部状態がリセットされます (preStart)

  4. エスカレート - スーパーバイザの親にチェーンをエスカレートします

したがって、SQLException再開したい と他のすべてを再開したい場合、コードは次のようになります。

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

Futureそれ自体が応答を返したときに何をすべきかに関する2番目の質問Failureです。この場合、結果としてどうなるかによると思い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
于 2013-07-22T13:04:35.497 に答える