Add retry logic for download

This commit is contained in:
Vadim Smal
2022-08-11 18:06:20 +01:00
parent d6355074b2
commit cb76934ca2
2 changed files with 69 additions and 4 deletions
@@ -77,7 +77,12 @@ class NetworkClientImpl: NetworkClient {
func download(_ url: URL, to location: URL, completion: @escaping (Result<Void, NetworkClientError>) -> Void) {
var request = URLRequest(url: url)
setupAuthenticationSignatureIfPresent(&request)
makeDownloadRequest(request, output: location, completion: completion)
makeDownloadRequest(
request,
output: location,
retries: maxRetries,
completion: completion
)
}
func upload(_ file: URL, as url: URL, completion: @escaping (Result<Void, NetworkClientError>) -> Void) {
@@ -125,7 +130,7 @@ class NetworkClientImpl: NetworkClient {
dataTask.resume()
}
private func makeDownloadRequest(_ request: URLRequest, output: URL, completion: @escaping (Result<Void, NetworkClientError>) -> Void) {
private func makeDownloadRequest(_ request: URLRequest, output: URL, retries: Int, completion: @escaping (Result<Void, NetworkClientError>) -> Void) {
guard fileManager.fileExists(atPath: output.path) == false else {
infoLog("Download file found in the destination, skipping download.")
completion(.success(()))
@@ -135,6 +140,17 @@ class NetworkClientImpl: NetworkClient {
let dataTask = session.downloadTask(with: request) { [fileManager] fileURL, _, error in
guard let fileURL = fileURL else {
let networkError = error.map(NetworkClientError.build) ?? .inconsistentSession
if retries > 0 {
infoLog("Download request failed with \(networkError). Left retries: \(retries).")
self.retryDownload(
request,
output: output,
retries: retries,
completion: completion,
after: self.retryDelay
)
return
}
errorLog("Download request failed: \(networkError)")
completion(.failure(networkError))
return
@@ -196,7 +212,24 @@ class NetworkClientImpl: NetworkClient {
private func retryUpload(_ request: URLRequest, input: URL, retries: Int, completion: @escaping (Result<Void, NetworkClientError>) -> Void, after: TimeInterval) {
DispatchQueue.global().asyncAfter(deadline: .now() + after) { [weak self] in
guard let self = self else { return }
self.makeUploadRequest(request, input: input, retries: retries - 1, completion: completion)
self.makeUploadRequest(
request,
input: input,
retries: retries - 1,
completion: completion
)
}
}
private func retryDownload(_ request: URLRequest, output: URL, retries: Int, completion: @escaping (Result<Void, NetworkClientError>) -> Void, after: TimeInterval) {
DispatchQueue.global().asyncAfter(deadline: .now() + after) { [weak self] in
guard let self = self else { return }
self.makeDownloadRequest(
request,
output: output,
retries: retries - 1,
completion: completion
)
}
}
}
@@ -167,7 +167,7 @@ class NetworkClientImplTests: XCTestCase {
func testUploadSuccessDoesntRetry() throws {
client = NetworkClientImpl(
session: session,
retries: 0,
retries: 2,
retryDelay: 0,
fileManager: fileManager,
awsV4Signature: nil
@@ -178,6 +178,38 @@ class NetworkClientImplTests: XCTestCase {
XCTAssertEqual(requests.map(\.url), [url], "Expected 1 request - original only")
}
func testDownloadFilureWith400Retries() throws {
client = NetworkClientImpl(
session: session,
retries: 2,
retryDelay: 0,
fileManager: fileManager,
awsV4Signature: nil
)
responses[url] = nil
_ = try waitForResponse({ client.download(url, to: fileURL, completion: $0) }, timeout: 0.5)
XCTAssertEqual(
requests.map(\.url),
Array(repeating: url, count: 3),
"Expected 3 requests (original + 2 retries)"
)
}
func testDownloadSuccessDoesntRetry() throws {
client = NetworkClientImpl(
session: session,
retries: 2,
retryDelay: 0,
fileManager: fileManager,
awsV4Signature: nil
)
responses[url] = .success(successResponse, Data())
_ = try waitForResponse { client.download(url, to: fileURL, completion: $0) }
XCTAssertEqual(requests.map(\.url), [url], "Expected 1 request - original only")
}
func testFileExits400CompletesWithFalse() throws {
responses[url] = .success(failureResponse, Data())
let response = try waitForResponse { client.fileExists(url, completion: $0) }