【问题标题】:What is the correct way to retry http calls from Akka Actors从 Akka Actors 重试 http 调用的正确方法是什么
【发布时间】:2017-06-22 11:02:50
【问题描述】:
我有一个对外部服务进行 Http 调用的演员。有时服务会以 Http 404 响应,有时还会出现 http 连接错误。再次重试时,这两个都消失了。
重试参与者请求的最佳方式是什么。
我能想到的是
使用主管策略并重启actor
在重试http调用的actor中使用递归方法,
最大重试次数
哪种方法是正确的,1 还是 2。我认为方法 1 对于像重试 Http 调用这样简单的事情来说太过分了。请分享您的建议。
【问题讨论】:
标签:
akka
akka-supervision
akka-actor
【解决方案1】:
我认为你的两种方法都是有效的。
在我看来,第一种方法是一种更被动的方法,即接受失败并让演员只做它应该做的事情(而不是让它处理重试等)
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之前将等待时间加倍,直到达到最大值。只有这样它才会停止尝试。
如果您更喜欢第二个选项,我不会使用递归方法,但会在一段时间后 schedule a message 向演员本身再次尝试 http 调用:
system.scheduler.scheduleOnce(1 seconds, self, TryAgain)
【解决方案2】:
我建议使用“之后”模式。这允许您在失败的情况下重复您的请求。像这样的:
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
}
}
}