Created
October 24, 2019 08:29
-
-
Save CassiusPacheco/a155c92bca482755ea8597016d302130 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import RxSwift | |
// Smart Retry idea originally from: http://kean.github.io/post/smart-retry | |
public enum DelayOptions { | |
case immediate | |
// Time is in milliseconds | |
case constant(time: Int) | |
// Initial is in milliseonds | |
case exponential(initial: Int, multiplier: Double) | |
func delay(_ attempt: Int) -> DispatchTimeInterval { | |
switch self { | |
case .immediate: | |
return .seconds(0) | |
case let .constant(time): | |
return .milliseconds(time) | |
case let .exponential(initial, multiplier): | |
return attempt == 1 ? .milliseconds(initial) : .milliseconds(Int(round(Double(initial) * pow(multiplier, Double(attempt - 1))))) | |
} | |
} | |
} | |
public struct RetryParams { | |
let maxAttemptCount: Int | |
let delayOption: DelayOptions | |
let scheduler: SchedulerType | |
let shouldRetry: (Error) -> Bool | |
public init(maxAttemptCount: Int = 0, | |
delayOption: DelayOptions = .immediate, | |
scheduler: SchedulerType = ConcurrentDispatchQueueScheduler(qos: .utility), | |
shouldRetry: @escaping (Error) -> Bool = { _ in false }) { | |
self.maxAttemptCount = maxAttemptCount | |
self.delayOption = delayOption | |
self.scheduler = scheduler | |
self.shouldRetry = shouldRetry | |
} | |
} | |
public extension ObservableType { | |
/// Retries the source observable sequence on error using a provided retry | |
/// strategy. | |
/// - parameter maxAttemptCount: Maximum number of times to repeat the | |
/// sequence. `Int.max` by default. | |
/// - parameter shouldRetry: Always returns `true` by default. | |
func retry(_ maxAttemptCount: Int = Int.max, delayOption: DelayOptions, scheduler: SchedulerType, shouldRetry: @escaping (Error) -> Bool = { _ in true }) -> Observable<Element> { | |
return retryWhen { (errors: Observable<Error>) in | |
return errors.enumerated().flatMap { attempt, error -> Observable<Void> in | |
guard shouldRetry(error), maxAttemptCount > attempt + 1 else { return .error(error) } | |
return Observable<Int> | |
.timer(delayOption.delay(attempt + 1), scheduler: scheduler) | |
.mapToVoid() | |
} | |
} | |
} | |
func retry(_ params: RetryParams) -> Observable<Element> { | |
return retry(params.maxAttemptCount, delayOption: params.delayOption, scheduler: params.scheduler, shouldRetry: params.shouldRetry) | |
} | |
} | |
public extension Observable { | |
/// Transforms any `Observable` into `Observable<Void>`. This is especially useful | |
/// when merging different observables using `Observable.merge(...)`. | |
/// - Returns: `Observable<Void>` | |
func mapToVoid() -> Observable<Void> { | |
return map { _ in return () } | |
} | |
} | |
public extension Single where Trait == SingleTrait { | |
/// Transforms any `Single` into `Single<Void>`. | |
/// - Returns: `Single<Void>` | |
func mapToVoid() -> Single<Void> { | |
return map { _ in return () } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment