重试来自 Akka Actors 的 http 调用的正确方法是什么

What is the correct way to retry http calls from Akka Actors

我有一个对外部服务进行 Http 调用的 actor。有时服务会响应 Http 404,有时也会出现 http 连接错误。再次重试时,这两个都会消失。

演员重试请求的最佳方法是什么。

我能想到的是

  1. 使用supervisor策略并重启actor

  2. 在重试 http 调用的 actor 中使用递归方法, 最大重试次数

哪个是正确的方法,1 或 2。我认为方法 1 对于像重试 Http 调用这样简单的事情来说有点矫枉过正。请分享您的建议。

我认为你的两种方法都是有效的。

在我看来,第一种方法是在接受失败并让 Actor 只做它应该做的事情(而不是让它处理重试等)方面更具反应性的方法

Akka 监督中内置了一个简洁的东西:BackoffSupervisor

在我看来,这非常适合 actor 由于外部因素而失败的问题,等待一段时间再试可能是有意义的(就像您使用 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 调用的 actor 本身:

system.scheduler.scheduleOnce(1 seconds, self, TryAgain)

我建议使用 "after" 模式。这允许您在失败的情况下重复您的请求。像这样:

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
    }
  }
}