1

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

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

我能想到的是

  1. 使用主管策略并重新启动actor

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

哪种方法是正确的,1 还是 2。我认为方法 1 对于像重试 Http 调用这样简单的事情来说是一种过度杀伤力。请分享您的建议。

4

2 回答 2

2

在我看来,你的两种方法都是有效的。

第一种方法在我看来是一种更被动的方式来做到这一点,即接受失败并让演员只做它应该做的事情(而不是让它处理重试等)

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)
于 2017-06-22T12:36:39.583 回答
1

我建议使用“之后”模式。这允许您在失败的情况下重复您的请求。像这样的东西:

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
    }
  }
}
于 2017-06-22T13:55:20.617 回答