-
Notifications
You must be signed in to change notification settings - Fork 212
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
retry / repeat (was: retryWithDelay) #15
Comments
I'd like to explore the possibility of having a dynamic retry mechanism. This would allow for exponential backoff scenarios, provided we do something like this:
enum RetryChoice {
case Immediate
case Delayed(Double)
case Cancelled
}
typealias RetryHandler = (attempts: Int, delays: [RetryChoice]) -> RetryChoice
extension ObservableType {
func retry(handler: RetryHandler) -> Observable<E> {
// ...
}
} Opinions? |
Ok more thoughts about this excellent idea for an operator. I think we can implement several possible variations to cover the full spectrum: Retry with a fixed delay at each iteration: Retry with a fixed delay increase at each iteration, optionally providing the initial delay: Retry with a growing delay as a percentage of previous delay: I am tempted to make |
I think we should also add a Therefore I suggest we do: Retry with a fixed delay at each iteration: Retry with a fixed delay increase at each iteration, optionally providing the initial delay: Retry with a growing delay as a percentage of previous delay: @brunogb what do you think about this? |
Hey @fpillet nice suggestions :) I think we could keep the enum approach and improve in the number of cases to cover full spectrum? enum RetryChoice {
case Immediate
case Delayed(Double)
case ExponentialDelayed(Double, Double)
case PercentageDelayed(Double, Double)
case CustomDelayTimer((Int-> Double))
case Cancelled
}
extension ObservableType {
func retry(maxAttempts: Int, choice: RetryChoice, scheduler : SchedulerType = MainScheduler.instance) -> Observable<E> {
// ...
}
} What do you think? |
The last one Also, since we are passing an enum, why not make |
Ah yes, I thought for the real code to have named parameters :) Should be something like this then: enum RetryChoice {
case Immediate (attempts: Int)
case Delayed (attempts: Int, time: Double)
case ExponentialDelayed (attempts: Int, initial: Double, multiplier: Double)
case PercentageDelayed (attempts: Int, initial: Double, percent: Double)
case CustomDelayTimer (attempts: Int, delayCalculator:(Int-> Double))
}
extension ObservableType {
func retry(choice: RetryChoice, scheduler : SchedulerType = MainScheduler.instance) -> Observable<E> {
// ...
}
} Also, maybe enum RetryChoice {
case Immediate (attempts: Int)
case Delayed (attempts: Int, time: Double)
case ExponentialDelayed (attempts: Int, initial: Double, multiplier: Double)
case CustomDelayTimer (attempts: Int, delayCalculator:(Int-> Double))
} |
Also we could rename enum RetryBehavior {
case Immediate (attempts: Int)
case Delayed (attempts: Int, time: Double)
case ExponentialDelayed (attempts: Int, initial: Double, multiplier: Double)
case CustomTimerDelayed (attempts: Int, delayCalculator:(Int-> Double))
}
extension ObservableType {
func retryWithBehavior(behavior: RetryBehavior, scheduler : SchedulerType = MainScheduler.instance) -> Observable<E> {
// ...
}
} |
I like this. I'd also like to add something similar for regular observable completion ( |
Actually while we are at it, we could go as far as: enum RepeatBehavior {
case Immediate (attempts: Int = .max)
case Delayed (attempts: Int, time: Double)
case ExponentialDelayed (attempts: Int, initial: Double, multiplier: Double)
case CustomTimerDelayed (attempts: Int, delayCalculator:(Int-> Double))
}
typealias RepeatPredicate = (ErrorType) -> Bool
extension ObservableType {
// retry with behavior on .Error. Complete on .Completed
func retry(behavior: RepeatBehavior, shouldRetry : RepeatPredicate? = nil, scheduler : SchedulerType = MainScheduler.instance) -> Observable<E> { }
// repeat with behavior on .Completed. Don't repeat on error
func repeat(behavior: RepeatBehavior, shouldRepeat : RepeatPredicate? = nil, scheduler : SchedulerType = MainScheduler.instance) -> Observable<E> { }
} That is, have a condition in addition to a behavior. Is that too much? I don't think so, as long as there's a default parameter for unconditional behavior. |
So thanks for @reloni's contribution, we now have a |
I love the |
Name and description
retryWithDelay(numberOfAttempts: Int, delayIncrease: Double)
Motivation for inclusion
Allows an operation to wait some time before trying again in case of error. Also allow for increment the waiting after each failed attempt
Example of use
We could use this operator like a "Retry to connect in" that we seen in many communicators app.
Sometimes it may be better to wait some time before trying an operation again.
Suggested implementation
This was a suggested implementation made by @mjohnson (on rxSwift slack). I plan to improve in this solution allowing for better parametrisation
The text was updated successfully, but these errors were encountered: