2016-09-16 107 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 
    }))