From f2e4557f4468593b6ed54a6d9d576544e087566d Mon Sep 17 00:00:00 2001 From: Pierre Mardon Date: Wed, 21 Aug 2024 16:37:01 +0200 Subject: [PATCH] Make MainActor friendly (#42) * Make it MainActor friendly, closes #39 * Fix missing @MainActor * Trigger CI --- .gitignore | 1 + Sources/SwiftRetrier/Core/Model/Policies/RetryPolicy.swift | 2 ++ .../Core/PolicyBuilding/GiveUpCriteriaPolicyWrapper.swift | 4 +++- .../Core/PolicyBuilding/RetryPolicy+GiveUpOn.swift | 2 +- Sources/SwiftRetrier/Core/Retriers/SimpleRetrier.swift | 4 +++- Sources/SwiftRetrier/DSL/ColdRepeater.swift | 6 +++--- Sources/SwiftRetrier/DSL/ColdRetrier.swift | 4 ++-- .../SwiftRetrier/TypeErasing/AnySingleOutputRetrier.swift | 2 +- 8 files changed, 16 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index b63bf7f..3f41081 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ xcuserdata/ DerivedData/ .swiftpm/ .netrc +Derived/ \ No newline at end of file diff --git a/Sources/SwiftRetrier/Core/Model/Policies/RetryPolicy.swift b/Sources/SwiftRetrier/Core/Model/Policies/RetryPolicy.swift index a45a000..e3ff168 100644 --- a/Sources/SwiftRetrier/Core/Model/Policies/RetryPolicy.swift +++ b/Sources/SwiftRetrier/Core/Model/Policies/RetryPolicy.swift @@ -1,6 +1,8 @@ import Foundation public protocol RetryPolicy: Sendable { + @MainActor func shouldRetry(on attemptFailure: AttemptFailure) -> RetryDecision + @MainActor func policyAfter(attemptFailure: AttemptFailure, delay: TimeInterval) -> any RetryPolicy } diff --git a/Sources/SwiftRetrier/Core/PolicyBuilding/GiveUpCriteriaPolicyWrapper.swift b/Sources/SwiftRetrier/Core/PolicyBuilding/GiveUpCriteriaPolicyWrapper.swift index f458077..ad2460e 100644 --- a/Sources/SwiftRetrier/Core/PolicyBuilding/GiveUpCriteriaPolicyWrapper.swift +++ b/Sources/SwiftRetrier/Core/PolicyBuilding/GiveUpCriteriaPolicyWrapper.swift @@ -1,6 +1,6 @@ import Foundation -public typealias GiveUpCriteria = @Sendable ( +public typealias GiveUpCriteria = @MainActor @Sendable ( _ attemptFailure: AttemptFailure, _ nestedPolicyDelay: TimeInterval ) -> Bool @@ -15,6 +15,7 @@ public struct GiveUpCriteriaPolicyWrapper: RetryPolicy { self.giveUpCriteria = giveUpCriteria } + @MainActor public func shouldRetry(on attemptFailure: AttemptFailure) -> RetryDecision { return switch wrapped.shouldRetry(on: attemptFailure) { case .giveUp: @@ -28,6 +29,7 @@ public struct GiveUpCriteriaPolicyWrapper: RetryPolicy { } } + @MainActor public func policyAfter(attemptFailure: AttemptFailure, delay: TimeInterval) -> any RetryPolicy { GiveUpCriteriaPolicyWrapper( wrapped: wrapped.policyAfter(attemptFailure: attemptFailure, delay: delay), diff --git a/Sources/SwiftRetrier/Core/PolicyBuilding/RetryPolicy+GiveUpOn.swift b/Sources/SwiftRetrier/Core/PolicyBuilding/RetryPolicy+GiveUpOn.swift index 1d38962..342340f 100644 --- a/Sources/SwiftRetrier/Core/PolicyBuilding/RetryPolicy+GiveUpOn.swift +++ b/Sources/SwiftRetrier/Core/PolicyBuilding/RetryPolicy+GiveUpOn.swift @@ -19,7 +19,7 @@ public extension RetryPolicy { } } - func giveUpOnErrors(matching finalErrorCriteria: @escaping @Sendable (Error) -> Bool) -> RetryPolicy { + func giveUpOnErrors(matching finalErrorCriteria: @escaping @Sendable @MainActor (Error) -> Bool) -> RetryPolicy { GiveUpCriteriaPolicyWrapper(wrapped: self) { attempt, _ in finalErrorCriteria(attempt.error) } diff --git a/Sources/SwiftRetrier/Core/Retriers/SimpleRetrier.swift b/Sources/SwiftRetrier/Core/Retriers/SimpleRetrier.swift index d9dcbef..3e7768b 100644 --- a/Sources/SwiftRetrier/Core/Retriers/SimpleRetrier.swift +++ b/Sources/SwiftRetrier/Core/Retriers/SimpleRetrier.swift @@ -71,7 +71,9 @@ public class SimpleRetrier: SingleOutputRetrier, @unchecked Se throw error case .retry(delay: let delay): try await Task.sleep(nanoseconds: nanoseconds(delay)) - policy = policy.policyAfter(attemptFailure: attemptFailure, delay: delay) + policy = await MainActor.run { [policy] in + policy.policyAfter(attemptFailure: attemptFailure, delay: delay) + } attemptIndex += 1 } } diff --git a/Sources/SwiftRetrier/DSL/ColdRepeater.swift b/Sources/SwiftRetrier/DSL/ColdRepeater.swift index 78e9595..7654c24 100644 --- a/Sources/SwiftRetrier/DSL/ColdRepeater.swift +++ b/Sources/SwiftRetrier/DSL/ColdRepeater.swift @@ -1,7 +1,7 @@ import Foundation -import Combine +@preconcurrency import Combine -public struct ColdRepeater { +public struct ColdRepeater: Sendable { let policy: RetryPolicy let repeatDelay: TimeInterval let conditionPublisher: AnyPublisher? @@ -24,7 +24,7 @@ public extension ColdRepeater { return ColdRepeater(policy: policy, repeatDelay: repeatDelay, conditionPublisher: conditionPublisher) } - func giveUpOnErrors(matching finalErrorCriteria: @escaping @Sendable (Error) -> Bool) -> ColdRepeater { + func giveUpOnErrors(matching finalErrorCriteria: @escaping @Sendable @MainActor (Error) -> Bool) -> ColdRepeater { let policy = policy.giveUpOnErrors(matching: finalErrorCriteria) return ColdRepeater(policy: policy, repeatDelay: repeatDelay, conditionPublisher: conditionPublisher) } diff --git a/Sources/SwiftRetrier/DSL/ColdRetrier.swift b/Sources/SwiftRetrier/DSL/ColdRetrier.swift index 2f34075..5140627 100644 --- a/Sources/SwiftRetrier/DSL/ColdRetrier.swift +++ b/Sources/SwiftRetrier/DSL/ColdRetrier.swift @@ -1,7 +1,7 @@ import Foundation import Combine -public struct ColdRetrier { +public struct ColdRetrier: @unchecked Sendable { let policy: RetryPolicy let conditionPublisher: AnyPublisher? } @@ -23,7 +23,7 @@ public extension ColdRetrier { return ColdRetrier(policy: policy, conditionPublisher: conditionPublisher) } - func giveUpOnErrors(matching finalErrorCriteria: @escaping @Sendable (Error) -> Bool) -> ColdRetrier { + func giveUpOnErrors(matching finalErrorCriteria: @escaping @Sendable @MainActor (Error) -> Bool) -> ColdRetrier { let policy = policy.giveUpOnErrors(matching: finalErrorCriteria) return ColdRetrier(policy: policy, conditionPublisher: conditionPublisher) } diff --git a/Sources/SwiftRetrier/TypeErasing/AnySingleOutputRetrier.swift b/Sources/SwiftRetrier/TypeErasing/AnySingleOutputRetrier.swift index 4bbd7a6..4267302 100644 --- a/Sources/SwiftRetrier/TypeErasing/AnySingleOutputRetrier.swift +++ b/Sources/SwiftRetrier/TypeErasing/AnySingleOutputRetrier.swift @@ -1,7 +1,7 @@ import Foundation import Combine -public class AnySingleOutputRetrier: AnyRetrier, SingleOutputRetrier, @unchecked Sendable { +public class AnySingleOutputRetrier: AnyRetrier, SingleOutputRetrier { private let outputBlock: @Sendable () async throws -> Output