ビジネス ロジックの例外を処理するために Akka Supervisor Strategy を使用しています。
最も有名な Scala ブログ シリーズNeophyteの 1 つを読んでいると、彼が私がいつもやってきたこととは別の目的を与えていることがわかりました。
例:
外部リソースに接続する必要がある HttpActor があり、それがダウンしている場合は、例外をスローしますResourceUnavailableException
。
スーパーバイザーがそれをキャッチした場合、HttpActor で Restart を呼び出し、HttpActorpreRestart
メソッドで do aschedulerOnce
を呼び出して再試行します。
俳優:
class HttpActor extends Actor with ActorLogging {
implicit val system = context.system
override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
log.info(s"Restarting Actor due: ${reason.getCause}")
message foreach { msg =>
context.system.scheduler.scheduleOnce(10.seconds, self, msg)
}
}
def receive = LoggingReceive {
case g: GetRequest =>
doRequest(http.doGet(g), g.httpManager.url, sender())
}
スーパーバイザー:
class HttpSupervisor extends Actor with ActorLogging with RouterHelper {
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = 5) {
case _: ResourceUnavailableException => Restart
case _: Exception => Escalate
}
var router = makeRouter[HttpActor](5)
def receive = LoggingReceive {
case g: GetRequest =>
router.route(g, sender())
case Terminated(a) =>
router = router.removeRoutee(a)
val r = context.actorOf(Props[HttpActor])
context watch r
router = router.addRoutee(r)
}
}
ここでのポイントは何ですか?
私のdoRequest
メソッドがResourceUnavailableException
. 私が見る利点は、再試行回数を無料で取得できることと、例外自体を処理する優れた方法です。
ブログを見ると、再試行が必要な場合に備えて、次のようなメッセージを送信するだけの別のアプローチを示しています。
def receive = {
case EspressoRequest =>
val receipt = register ? Transaction(Espresso)
receipt.map((EspressoCup(Filled), _)).recover {
case _: AskTimeoutException => ComebackLater
} pipeTo(sender)
case ClosingTime => context.system.shutdown()
}
ここで の場合AskTimeoutException
、Future
彼は結果をオブジェクトとしてパイプしComebackLater
、これを処理します。
case ComebackLater =>
log.info("grumble, grumble")
context.system.scheduler.scheduleOnce(300.millis) {
coffeeSource ! EspressoRequest
}
私にとって、これは戦略スーパーバイザーでできることのほとんどですが、再試行ロジックが組み込まれていない手動の方法です。
では、ここでの最善のアプローチは何ですか?またその理由は何ですか? akka スーパーバイザー戦略を使用するという私の概念は完全に間違っていますか?