Акка: Как объединить OneForOneStrategy и AllForOneStrategy

Если я определю стратегию супервизора для актера в Scala, как я могу использовать оба OneForOneStrategy и AllForOneStrategy? Есть ли простой способ объединить их или мне нужно определить пользовательский SupervisorStrategy? Вот пример:

class MyActor extends Actor {
  override val supervisorStrategy = OneForOneStrategy() {
    case _: NullPointerException  => Restart
    case _: FileNotFoundException => Restart // here I want to restart all children
    case _: Exception             => Escalate
  }
}

Если мне нужно написать собственную стратегию супервизора, как я могу это сделать? Я не нашел примера для этого.

1 ответ

Решение

Вы должны будете определить собственную стратегию супервизора. Для вашего конкретного случая использования будет работать следующая пользовательская стратегия:

package akka.actor

import java.io.FileNotFoundException
import scala.concurrent.duration._

case class CustomStrategy(
  maxNrOfRetries:              Int      = -1,
  withinTimeRange:             Duration = Duration.Inf,
  override val loggingEnabled: Boolean  = true)(val decider: SupervisorStrategy.Decider)
  extends SupervisorStrategy {

  import SupervisorStrategy._

  private val retriesWindow = (maxNrOfRetriesOption(maxNrOfRetries), withinTimeRangeOption(withinTimeRange).map(_.toMillis.toInt))

  def handleChildTerminated(context: ActorContext, child: ActorRef, children: Iterable[ActorRef]): Unit = ()

  def processFailure(context: ActorContext, restart: Boolean, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Unit = {
    if (cause.isInstanceOf[FileNotFoundException]) {
      // behave like AllForOneStrategy
      if (children.nonEmpty) {
        if (restart && children.forall(_.requestRestartPermission(retriesWindow)))
          children foreach (crs ⇒ restartChild(crs.child, cause, suspendFirst = (crs.child != child)))
        else
          for (c ← children) context.stop(c.child)
      }
    } else {
      // behave like OneForOneStrategy
      if (restart && stats.requestRestartPermission(retriesWindow))
        restartChild(child, cause, suspendFirst = false)
      else
        context.stop(child)
    }
  }
}

Вот суть, которая проверяет вышеуказанную стратегию. Спецификация создает супервизор, который использует CustomStrategy и это создает двух детей. Когда один ребенок бросает NullPointerException только тот ребенок перезапущен; когда ребенок бросает FileNotFoundException Оба ребенка перезапускаются.

Несколько замечаний о пользовательской стратегии:

  • Расширяется SupervisorStrategy и моделируется после существующих стратегий, определенных здесь.
  • Он определяется внутри akka.actor Пакет, чтобы иметь доступ к пакету частных членов там.
  • processFailure, один из методов, который должен быть переопределен в классах, которые расширяют SupervisorStrategy называется Restart а также Stop так что для вашего сценария мы определяем пользовательское поведение там.
Другие вопросы по тегам