我有一个在应用程序启动时创建的actor作为另一个actor的子节点,并且每天从父节点接收一条消息,以执行从某些SFTP服务器获取某些文件的操作。
现在,可能存在一些导致操作失败的次要临时连接异常。在这种情况下,需要重试。
但是可能存在抛出异常并且不会在重试时解决的情况(例如:未找到文件,某些配置不正确等)。
因此,在这种情况下,考虑到演员将在很长一段时间(每天一次)之后接收消息,这可能是一个适当的重试机制和监督策略。
在这种情况下,发送给actor的消息输入不错 - 它只是一个触发器。示例:
case object FileFetch
如果我在这样的父母中有一个监督策略,它将在没有重试的情况下重新启动每个次要/主要异常的失败子项。
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = -1, withinTimeRange = Duration.inf) {
case _: Exception => Restart
}
我想拥有的是这样的:
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = -1, withinTimeRange = Duration.inf) {
case _: MinorException => Retry same message 2, 3 times and then Restart
case _: Exception => Restart
}
答案 0 :(得分:3)
如果发生异常,“重试”或重新发送消息是您必须自己实现的。来自documentation:
如果在处理邮件时抛出异常(即从邮箱中取出并移交给当前行为),则此邮件将丢失。重要的是要了解它没有放回邮箱。因此,如果要重试处理消息,则需要通过捕获异常并重试流程来自行处理。确保您对重试次数设置了限制,因为您不希望系统活锁(因此消耗了大量的cpu周期而没有取得进展)。
如果您想在FileFetch
的情况下向孩子重新发送MinorException
消息而不重新启动孩子,那么您可以在孩子中捕获异常以避免触发监督策略。在try-catch块中,您可以向父节点发送消息,并让父节点跟踪重试次数(例如,如果您希望父节点制定某种退避策略,则可能在此消息中包含时间戳) 。在孩子身上:
def receive = {
case FileFetch =>
try {
...
} catch {
case m: MinorException =>
val now = System.nanoTime
context.parent ! MinorIncident(self, now)
}
case ...
}
在父母:
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = -1, withinTimeRange = Duration.Inf) {
case _: Exception => Restart
}
var numFetchRetries = 0
def receive = {
case MinorIncident(fetcherRef, time) =>
log.error(s"${fetcherRef} threw a MinorException at ${time}")
if (numFetchRetries < 3) { // possibly use the time in the retry logic; e.g., a backoff
numFetchRetries = numFetchRetries + 1
fetcherRef ! FileFetch
} else {
numFetchRetries = 0
context.stop(fetcherRef)
... // recreate the child
}
case SomeMsgFromChildThatFetchSucceeded =>
numFetchRetries = 0
case ...
}
或者,不是在子代中捕获异常,而是在Resume
的情况下将主管策略设置为MinorException
子进程,同时仍然让父进程处理消息重试逻辑:
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = -1, withinTimeRange = Duration.Inf) {
case m: MinorException =>
val child = sender()
val now = System.nanoTime
self ! MinorIncident(child, now)
Resume
case _: Exception => Restart
}