scala - Akka Supervisor 策略 - 正确的用例

标签 scala akka akka-supervision

我一直在使用 Akka Supervisor Strategy 来处理业务逻辑异常。

阅读最著名的 Scala 博客系列之一 Neophyte ,我发现他为我一直在做的事情赋予了不同的目的。

例子:

假设我有一个 HttpActor 应该联系外部资源,如果它关闭,我会抛出一个异常,现在是 ResourceUnavailableException .

如果我的主管发现了这一点,我将在我的 HttpActor 和我的 HttpActor preRestart 中调用 Restart方法,我会调用做一个 schedulerOnce重试。

Actor :

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()
}

在此情况下 AskTimeoutExceptionFuture ,他将结果输出为 ComebackLater对象,他将处理这样做:
case ComebackLater =>
      log.info("grumble, grumble")
      context.system.scheduler.scheduleOnce(300.millis) {
        coffeeSource ! EspressoRequest
      }

对我来说,这几乎是你可以用策略主管做的事情,但以手动方式,没有内置的重试次数逻辑。

那么这里最好的方法是什么,为什么?我使用 akka 主管策略的概念是完全错误的吗?

最佳答案

您可以使用 BackoffSupervisor :

Provided as a built-in pattern the akka.pattern.BackoffSupervisor implements the so-called exponential backoff supervision strategy, starting a child actor again when it fails, each time with a growing time delay between restarts.


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
    }))

关于scala - Akka Supervisor 策略 - 正确的用例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39522429/

相关文章:

java - 检查文件是否存在于嵌套的不均匀目录中?

scala - 如何用尾部映射列表项[Scala]

java - 在 AKKA 中,调用 supervisor 的 shutdown 会停止它所监督的所有 actor 吗?

eclipse - SBT 从工作区本地解析

scala - 如何在 Actor 中包装 REST API 客户端

java - 聊天服务和持久性

java - 用于阻止请求的 Akka actor 池

scala - 使用 Akka Streams 动态压缩 List[Source[ByteString, NotUsed]]

java - Akka:测试主管推荐