-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Fix FlagApplier async behaviour #70
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,14 +26,14 @@ final class NetworkClient: HttpClient { | |
retry: Retry = .none | ||
) { | ||
self.session = | ||
session | ||
?? { | ||
let configuration = URLSessionConfiguration.default | ||
configuration.timeoutIntervalForRequest = timeout | ||
configuration.httpAdditionalHeaders = defaultHeaders | ||
session | ||
?? { | ||
let configuration = URLSessionConfiguration.default | ||
configuration.timeoutIntervalForRequest = timeout | ||
configuration.httpAdditionalHeaders = defaultHeaders | ||
|
||
return URLSession(configuration: configuration) | ||
}() | ||
return URLSession(configuration: configuration) | ||
}() | ||
|
||
self.headers = defaultHeaders | ||
self.retry = retry | ||
|
@@ -44,67 +44,56 @@ final class NetworkClient: HttpClient { | |
func post<T: Decodable>( | ||
path: String, | ||
data: Codable, | ||
completion: @escaping (HttpClientResult<T>) -> Void | ||
) throws { | ||
completion: @escaping (HttpClientResult<T>) async -> Void | ||
) async throws { | ||
let request = try buildRequest(path: path, data: data) | ||
perform(request: request, retry: self.retry) { response, data, error in | ||
await perform(request: request, retry: self.retry) { response, data, error in | ||
if let error { | ||
completion(.failure(error)) | ||
await completion(.failure(error)) | ||
return | ||
} | ||
|
||
guard let response, let data else { | ||
completion(.failure(ConfidenceError.internalError(message: "Bad response"))) | ||
await completion(.failure(ConfidenceError.internalError(message: "Bad response"))) | ||
return | ||
} | ||
|
||
do { | ||
let httpClientResult: HttpClientResponse<T> = | ||
try self.buildResponse(response: response, data: data) | ||
completion(.success(httpClientResult)) | ||
try self.buildResponse(response: response, data: data) | ||
await completion(.success(httpClientResult)) | ||
} catch { | ||
completion(.failure(error)) | ||
await completion(.failure(error)) | ||
} | ||
} | ||
} | ||
|
||
private func perform( | ||
request: URLRequest, | ||
retry: Retry, | ||
completion: @escaping (HTTPURLResponse?, Data?, Error?) -> Void | ||
) { | ||
completion: @escaping (HTTPURLResponse?, Data?, Error?) async -> Void | ||
) async { | ||
let retryHandler = retry.handler() | ||
let retryWait: TimeInterval? = retryHandler.retryIn() | ||
|
||
self.session.dataTask(with: request) { data, response, error in | ||
if let error { | ||
if self.shouldRetry(error: error), let retryWait { | ||
DispatchQueue.main.asyncAfter(deadline: .now() + retryWait) { | ||
self.perform(request: request, retry: retry, completion: completion) | ||
} | ||
return | ||
} else { | ||
completion(nil, nil, error) | ||
} | ||
} | ||
|
||
do { | ||
let (data, response) = try await self.session.data(for: request) | ||
guard let httpResponse = response as? HTTPURLResponse else { | ||
completion(nil, nil, HttpClientError.invalidResponse) | ||
await completion(nil, nil, HttpClientError.invalidResponse) | ||
return | ||
} | ||
|
||
if self.shouldRetry(httpResponse: httpResponse), let retryWait { | ||
DispatchQueue.main.asyncAfter(deadline: .now() + retryWait) { | ||
self.perform(request: request, retry: retry, completion: completion) | ||
} | ||
try? await Task.sleep(nanoseconds: UInt64(retryWait * 1_000_000_000)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty sure there is a better way to achieve this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like |
||
await self.perform(request: request, retry: retry, completion: completion) | ||
return | ||
} | ||
|
||
if let data { | ||
completion(httpResponse, data, nil) | ||
await completion(httpResponse, data, nil) | ||
} catch { | ||
if self.shouldRetry(error: error), let retryWait { | ||
try? await Task.sleep(nanoseconds: UInt64(retryWait * 1_000_000_000)) | ||
await self.perform(request: request, retry: retry, completion: completion) | ||
} else { | ||
let error = ConfidenceError.internalError(message: "Unable to complete request") | ||
completion(httpResponse, nil, error) | ||
await completion(nil, nil, error) | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error
is not returned from.data()
, while that was the case with.dataTask()
. However,.data()
is marked as throwing, so the do/catch wrapping should in practice replicate the exact same behaviour of.dataTask()