diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f67b61..5e1778d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. ## [Unreleased] ## Added +- Implement error handling in RetryPolicyService + - Added in Pull Request [#5](https://github.com/space-code/typhoon/pull/5). - Implement exponential backoff with jitter - Added in Pull Request [#4](https://github.com/space-code/typhoon/pull/4). diff --git a/Sources/Typhoon/Classes/RetryPolicyService/IRetryPolicyService.swift b/Sources/Typhoon/Classes/RetryPolicyService/IRetryPolicyService.swift index a4fa2ec..44f8829 100644 --- a/Sources/Typhoon/Classes/RetryPolicyService/IRetryPolicyService.swift +++ b/Sources/Typhoon/Classes/RetryPolicyService/IRetryPolicyService.swift @@ -13,10 +13,15 @@ public protocol IRetryPolicyService { /// /// - Parameters: /// - strategy: The strategy defining the behavior of the retry policy. + /// - onFailure: An optional closure called on each failure to handle or log errors. /// - closure: The closure that will be retried based on the specified strategy. /// /// - Returns: The result of the closure's execution after retrying based on the policy. - func retry(strategy: RetryPolicyStrategy?, _ closure: () async throws -> T) async throws -> T + func retry( + strategy: RetryPolicyStrategy?, + onFailure: ((Error) async -> Void)?, + _ closure: () async throws -> T + ) async throws -> T } public extension IRetryPolicyService { @@ -27,6 +32,17 @@ public extension IRetryPolicyService { /// /// - Returns: The result of the closure's execution after retrying based on the policy. func retry(_ closure: () async throws -> T) async throws -> T { - try await retry(strategy: nil, closure) + try await retry(strategy: nil, onFailure: nil, closure) + } + + /// Retries a closure with a given strategy. + /// + /// - Parameters: + /// - strategy: The strategy defining the behavior of the retry policy. + /// - closure: The closure that will be retried based on the specified strategy. + /// + /// - Returns: The result of the closure's execution after retrying based on the policy. + func retry(strategy: RetryPolicyStrategy?, _ closure: () async throws -> T) async throws -> T { + try await retry(strategy: strategy, onFailure: nil, closure) } } diff --git a/Sources/Typhoon/Classes/RetryPolicyService/RetryPolicyService.swift b/Sources/Typhoon/Classes/RetryPolicyService/RetryPolicyService.swift index 6f11c41..e7e5d18 100644 --- a/Sources/Typhoon/Classes/RetryPolicyService/RetryPolicyService.swift +++ b/Sources/Typhoon/Classes/RetryPolicyService/RetryPolicyService.swift @@ -27,13 +27,19 @@ public final class RetryPolicyService { // MARK: IRetryPolicyService extension RetryPolicyService: IRetryPolicyService { - public func retry(strategy: RetryPolicyStrategy?, _ closure: () async throws -> T) async throws -> T { + public func retry( + strategy: RetryPolicyStrategy?, + onFailure: ((Error) async -> Void)?, + _ closure: () async throws -> T + ) async throws -> T { for duration in RetrySequence(strategy: strategy ?? self.strategy) { try Task.checkCancellation() do { return try await closure() - } catch {} + } catch { + await onFailure?(error) + } try await Task.sleep(nanoseconds: duration) } diff --git a/Tests/TyphoonTests/UnitTests/RetryPolicyServiceTests.swift b/Tests/TyphoonTests/UnitTests/RetryPolicyServiceTests.swift index d77d7ea..c111512 100644 --- a/Tests/TyphoonTests/UnitTests/RetryPolicyServiceTests.swift +++ b/Tests/TyphoonTests/UnitTests/RetryPolicyServiceTests.swift @@ -60,6 +60,22 @@ final class RetryPolicyServiceTests: XCTestCase { // then XCTAssertEqual(counter, .retry) } + + func test_thatRetryServiceHandlesErrorOnFailureCallback_whenErrorOcurred() async { + // when + var failureError: NSError? + do { + _ = try await sut.retry( + strategy: .constant(retry: .retry, duration: .nanoseconds(1)), + onFailure: { error in failureError = error as NSError } + ) { + throw URLError(.unknown) + } + } catch {} + + // then + XCTAssertEqual(failureError as? URLError, URLError(.unknown)) + } } // MARK: - Constants