我有一个对外部服务进行 Http 调用的演员。有时服务会以 Http 404 响应,有时还会出现 http 连接错误。再次重试时,这两个都消失了。
重试演员请求的最佳方式是什么。
我能想到的是
使用主管策略并重新启动actor
在重试http调用的actor中使用递归方法,最大重试次数
哪种方法是正确的,1 还是 2。我认为方法 1 对于像重试 Http 调用这样简单的事情来说是一种过度杀伤力。请分享您的建议。
我有一个对外部服务进行 Http 调用的演员。有时服务会以 Http 404 响应,有时还会出现 http 连接错误。再次重试时,这两个都消失了。
重试演员请求的最佳方式是什么。
我能想到的是
使用主管策略并重新启动actor
在重试http调用的actor中使用递归方法,最大重试次数
哪种方法是正确的,1 还是 2。我认为方法 1 对于像重试 Http 调用这样简单的事情来说是一种过度杀伤力。请分享您的建议。
在我看来,你的两种方法都是有效的。
第一种方法在我看来是一种更被动的方式来做到这一点,即接受失败并让演员只做它应该做的事情(而不是让它处理重试等)
Akka Supervision 内置了一个巧妙的东西: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之前将等待时间加倍,直到达到最大值。只有这样它才会停止尝试。
如果您更喜欢第二种选择,我不会使用递归方法,而是会在一段时间后向参与者本身安排一条消息以再次尝试 http 调用:
system.scheduler.scheduleOnce(1 seconds, self, TryAgain)
我建议使用“之后”模式。这允许您在失败的情况下重复您的请求。像这样的东西:
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
}
}
}