我有一个让Http调用外部服务的actor。有时服务响应Http 404,有时也会出现http连接错误。再次重试时,这些都消失了。
演员重试请求的最佳方法是什么?
我能想到的是
使用主管策略并重新启动actor
在重试http调用的actor中使用递归方法, 最大重试次数
哪种方法是正确的,1或2.我认为方法1对于像重试Http调用这样简单的事情来说是一种过度杀伤。请分享您的推荐。
答案 0 :(得分:2)
在我看来,你的两种方法都是有效的。
在我看来,第一种方法是采取更为积极的方式来接受失败并让演员只做他们应该做的事情(而不是让它处理重试等)。
在Akka监督中建立了一个整洁的东西:BackoffSupervisor
在我看来,这非常适合演员因外部因素而失败的问题,等待一段时间再试一次是有意义的(如你的http调用情况)。
来自文档:
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
))
您可以定义最小和最大退避,并且主管将在尝试重新启动actor之前将等待时间加倍,直到达到最大值。只有这样它才会停止尝试。
如果您更喜欢第二个选项,我不会使用递归方法,但会在一段时间后再次向演员本身schedule a message再次尝试http调用:
system.scheduler.scheduleOnce(1 seconds, self, TryAgain)
答案 1 :(得分:0)
我建议使用“后”模式。这允许您在失败的情况下重复您的请求。像这样:
def retryRequest(ref: ActorRef, attemptsNumber: Int, step: Int)(
implicit ac: ActorSystem): Future[HttpResponse] = {
implicit val timeout = Timeout(5 seconds)
implicit val ec = ac.dispatcher
val s1 = after[HttpResponse](5 seconds, ac.scheduler) {
Http().singleRequest(HttpRequest(uri = "http://akka.io"))
}
s1 flatMap { res =>
res match {
case HttpResponse(StatusCodes.NotFound, headers, entity, _) => {
if(step < attemptsNumber)
retryRequest(ref, attemptsNumber, (step + 1))
else
s1
}
case HttpResponse(StatusCodes.OK, headers, entity, _) => s1
}
}
}