2016-09-16 101 views
2

我一直使用Akka Supervisor策略來處理業務邏輯異常。Akka Supervisor策略 - 正確使用案例

閱讀最有名的斯卡拉博客系列Neophyte之一,我發現他爲我一直在做的事情提供了不同的目的。

例子:

比方說,我有一個HttpActor應該接觸外部資源的情況下,它的下跌,我會拋出異常,現在一個ResourceUnavailableException

如果我的主管發現了這個問題,我將在我的HttpActor上調用Restart,並在我的HttpActor preRestart方法中,我將調用do schedulerOnce來重試該操作。

演員:

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,主管將會得到它,並重新啓動actor,迫使它在一段時間後重新發送消息,根據調度程序。我看到的好處是我可以免費獲得重試次數以及處理異常本身的好方法。

現在看博客,他表示有不同的方法,您需要重試的東西,只是發送消息是這樣的:

def receive = { 
    case EspressoRequest => 
    val receipt = register ? Transaction(Espresso) 
    receipt.map((EspressoCup(Filled), _)).recover { 
     case _: AskTimeoutException => ComebackLater 
    } pipeTo(sender) 

    case ClosingTime => context.system.shutdown() 
} 

在這裏,在的FutureAskTimeoutException情況下,他管的結果作爲一個ComebackLater對象,他會處理這樣做:

case ComebackLater => 
     log.info("grumble, grumble") 
     context.system.scheduler.scheduleOnce(300.millis) { 
     coffeeSource ! EspressoRequest 
     } 

對我來說這是相當多的,你可以與策略主管做什麼,但在手動方式,沒有內置的重試邏輯的數量。

那麼這裏最好的辦法是什麼?爲什麼?我的使用akka監督策略的概念是否完全錯誤?

回答

3

您可以使用BackoffSupervisor

提供的內置模式akka.pattern.BackoffSupervisor實現了所謂的指數退避監管策略,重新開始一個兒童演員在失敗時,每次用越來越多的時間延遲在重新啓動之間。

val supervisor = BackoffSupervisor.props(
    Backoff.onFailure(
    childProps, 
    childName = "myEcho", 
    minBackoff = 3.seconds, 
    maxBackoff = 30.seconds, 
    randomFactor = 0.2 // adds 20% "noise" to vary the intervals slightly 
).withAutoReset(10.seconds) // the child must send BackoffSupervisor.Reset to its parent 
    .withSupervisorStrategy(
    OneForOneStrategy() { 
     case _: MyException => SupervisorStrategy.Restart 
     case _ => SupervisorStrategy.Escalate 
    }))