Skip to content

Instantly share code, notes, and snippets.

@CassiusPacheco
Created October 24, 2019 08:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CassiusPacheco/a155c92bca482755ea8597016d302130 to your computer and use it in GitHub Desktop.
Save CassiusPacheco/a155c92bca482755ea8597016d302130 to your computer and use it in GitHub Desktop.
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