Search code examples
scalapostakkaakka-http

How to add retries to POST request in akka http?


I am doing a POST request with the following akka http request side api.

   Http().singleRequest(....)

I found that akka http for post doesn't support retries.

// max-retries = 3 // AKKA http default value is 5, and it doesn't work for POST request

Then what would be the best approach for doing a retry in case of POST request .


Solution

  • You can try something like this, based on akka.pattern.retry

    object Example {
    
      case class RetryConfig(attempts: Int, minBackoff: FiniteDuration, maxBackoff: FiniteDuration, randomFactor: Double)
    
      class SingleRequestClient(implicit system: ActorSystem) {
    
        def request(request: HttpRequest): Future[HttpResponse] = {
          Http().singleRequest(request)
        }
      }
    
      object SingleRequestClient {
    
        def apply(implicit system: ActorSystem): SingleRequestClient = {
          new SingleRequestClient
        }
    
        def apply(config: RetryConfig)(implicit system: ActorSystem, ex: ExecutionContext): SingleRequestClient = {
          new SingleRequestClient {
    
        override def request(request: HttpRequest): Future[HttpResponse] = {
          akka.pattern.retry(
            attempt = () => super.request(request),
            attempts = config.attempts,
            minBackoff = config.minBackoff,
            maxBackoff = config.maxBackoff,
            randomFactor = config.randomFactor
          )(ex, system.scheduler)
        }
          }
        }
      }
    }
    

    Additionally, You should set max-retries to 0.

    Ofc it works only with Future.failed so if you want to retry request on status != 200, you can change the basic implementation a little

      class SingleRequestClient(implicit system: ActorSystem, ex: ExecutionContext) {
    
        def request(request: HttpRequest): Future[HttpResponse] = {
          Http().singleRequest(request).map {
            case res: HttpResponse if res.status.isSuccess => res
            case res: HttpResponse if res.status.isFailure =>
              throw new Exception(s"Cannot process request dou to ${res.status.intValue} status")
          }
        }
      }