Акка - как сказать системе, что делать после достижения максимальных попыток стратегии?
Предполагая, супервизор актер определил определенную стратегию:
private static SupervisorStrategy strategy =
new OneForOneStrategy(10, Duration.create("1 minute"), DeciderBuilder.
match(Exception.class, e -> resume()).
matchAny(o -> escalate()).build());
И скажем, актеру дали указание возобновить, но он потерпел неудачу в 11-й раз за текущую продолжительность.
Что происходит сейчас?
Является ли родительский актер обостряет проблему?
Может ли он теперь как-то остановить актера упорядоченным способом (например, сказать дочернему актору закрыть соединение с БД)?
Есть ли другой метод overide для вызова в этом случае?
1 ответ
Супервизор актера может отправить сообщение ребенку, чтобы остановить DB, когда он получил сообщение об эскалации от контролируемого актера.
maxNrOfRetries
а также withinTimeRange
параметры в OneForOneStrategy
применять только к restart()
; они не вступают в игру для resume()
, В вашем случае, если контролируемый ребенок выдает исключение 11 раз, независимо от того, произойдет ли это в течение одной минуты, оно возобновляется 11 раз.
Ваша стратегия наблюдения в первую очередь соответствует Exception
, который охватывает самые исключительные условия, которые ваш актер может бросить, в этом случае resume()
используется. Стратегия во-вторых соответствует не Exception
(т.е. Error
), в таком случае escalate()
используется. Так что если Error
брошен в ребенка, родитель не обостряет проблему.
Для отслеживания количества возобновлений родительский субъект может содержать Map
из ActorRef
и количество раз, которое ребенок возобновил. Это возможно, потому что sender
в стратегии есть ссылка на неудавшегося ребенка. После достижения определенного порога родитель может отправить ребенку сообщение, например, чтобы он очистил ресурсы и остановился сам. Что-то вроде следующего (пример в Scala, но вы можете реализовать его в Java):
class Parent extends Actor {
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) {
case _: Exception =>
val child = sender
resumeCounts.get(child) match {
case Some(count) if count == resumeMax =>
child ! StopDB
case Some(count) =>
resumeCounts = resumeCounts + (child -> count + 1)
case None =>
resumeCounts = resumeCounts + (child -> 1)
}
Resume
case _ => Escalate
}
val resumeMax = 10
var resumeCounts: Map[ActorRef, Int] = Map.empty[ActorRef, Int]
def receive = ???
}
Вы можете сохранить временную метку со счетчиком, если хотите проверить количество повторений в течение продолжительности.
За restart()
Как указано здесь, "дочерний субъект останавливается, если число перезапусков превышает maxNrOfRetries
в течение withinTimeRange
продолжительность."Если вы перезапустили ребенка вместо того, чтобы возобновить его, вы могли бы поместить логику очистки в ребенка postStop
крюк. Когда максимальное количество повторов в пределах временного окна превышено, дочерний элемент останавливается и postStop
называется.