Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to do Alamofire requests with retries

I have a lot of places in the code where Alamofire request/response are handled.

Each of this requests may fail because of some intermittent problem (the most common is flaky network).

I would like to be able to retry requests 3 times before bailing out.

The straightforward method would be to having something like that

var errorCount = 0
func requestType1() {
   let request = Alamofire.request(...).responseJSON { response in
       if (isError(response) && errorCount < 3) {
          errorCount += 1
          request1()
       } 
       if (isError(response)) {
          handleError()
       }

       handleSuccess()
   }
}

However, I dislike this approach A LOT for multiple reasons. The most obvious is that I will need to implement such code for each request type (and I have something like 15 of them).

I am curios whether there is way to do something like (where the changes are minimal and non intrusive)

let request = Alamofire.request(..., **3**) 
like image 921
Victor Ronin Avatar asked May 24 '16 19:05

Victor Ronin


People also ask

What is the advantage of Alamofire?

Alamofire makes developing networking layers easier, faster and much cleaner. Another great benefit of using it is that it can be studied and its code is available. This can help programmers because it's a well-written framework.

Is Alamofire asynchronous?

Everything with Alamofire is asynchronous, which means you'll update the UI in an asynchronous manner: Hide the upload button, and show the progress view and activity view. While the file uploads, you call the progress handler with an updated percent.


2 Answers

Alamofire 4.0 has a RequestRetrier protocol you can use.

https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%204.0%20Migration%20Guide.md#request-retrier

Example:

class OAuth2Handler: RequestAdapter, RequestRetrier {
    public func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: RequestRetryCompletion) {
        if let response = request.task.response as? HTTPURLResponse, response.statusCode == 401 {
            completion(true, 1.0) // retry after 1 second
        } else {
            completion(false, 0.0) // don't retry
        }

        // Or do something with the retryCount
        // i.e. completion(request.retryCount <= 10, 1.0)
    }
}

let sessionManager = SessionManager()
sessionManager.retrier = OAuth2Handler()

sessionManager.request(urlString).responseJSON { response in
    debugPrint(response)
}
like image 191
iwasrobbed Avatar answered Oct 04 '22 18:10

iwasrobbed


I've had the same problem, and I got the requests to be retried using the RequestRetrier, should method and request.retryCount. Something like it:

// MARK: - RequestRetry

public func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
    lock.lock() ; defer { lock.unlock() }


    if let response = request.task?.response as? HTTPURLResponse{
        if response.statusCode == 401 {
            requestsToRetry.append(completion)

            getToken { (expires, _) in
               _ = SessionCountdownToken.sharedInstance.startCount(expirationTime: expires)
            }
        } else {

            if request.retryCount == 3 { completion(false, 0.0 ); return}
            completion(true, 1.0)
            return
        }
    } else {
        completion(false, 0.0)
    }
}
like image 33
Carla Camargo Avatar answered Oct 04 '22 17:10

Carla Camargo