'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**)
Solution 1:[1]
Alamofire 4.0 has a RequestRetrier protocol you can use.
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)
}
Solution 2:[2]
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)
}
}
Solution 3:[3]
I've created one wrapper class for request retrier should function. https://gist.github.com/daljeetseera/7ce2b53b8a88d8a5e9b172c0495c6455
And used the request retrier in session manager required for request.
static let sharedManager: SessionManager = {
let configuration = URLSessionConfiguration.default
let manager = Alamofire.SessionManager(configuration: configuration)
let requestRet = NetworkRequestRetrier()
manager.retrier = requestRet
return manager
}()
Solution 4:[4]
Alamofire 5 and Above
Alamofire provides an inbuilt class RetryPolicy which confirms to RequestRetrier protocol. RetryPolicy provides a default implementation to retry requests which failed due to system errors, such as network connectivity. source
Set the RetryPolicy while creating the Alamofire.Session object in the NetworkClient
class NetworkClient {
private let session: Alamofire.Session = {
let session = Session(interceptor: RetryPolicy())
return session
}()
....
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Tin Can |
| Solution 3 | |
| Solution 4 | Suhit Patil |
