Skip to content

Commit

Permalink
Merge pull request #496 from tjnet/deferred_retry_from_rex
Browse files Browse the repository at this point in the history
Add retry(upTo:interval:on:)
  • Loading branch information
mdiep committed Aug 7, 2017
2 parents d4b9a54 + aeee063 commit 4c0e12b
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -1,6 +1,9 @@
# master
*Please add new entries at the top.*

1. New method ``retry(upTo:interval:on:)``. This delays retrying on failure by `interval` until hitting the `upTo` limitation.


# 2.0.0
# 2.0.0-rc.3
1. `Lifetime.+=` which ties a `Disposable` to a `Lifetime`, is now part of the public API and is no longer deprecated.
Expand Down
34 changes: 34 additions & 0 deletions Sources/SignalProducer.swift
Expand Up @@ -1817,6 +1817,40 @@ extension SignalProducer {
}
}

/// Delays retrying on failure by `interval` up to `count` attempts.
///
/// - precondition: `count` must be non-negative integer.
///
/// - parameters:
/// - count: Number of retries.
/// - interval: An interval between invocations.
/// - scheduler: A scheduler to deliver events on.
///
/// - returns: A signal producer that restarts up to `count` times.
public func retry(upTo count: Int, interval: TimeInterval, on scheduler: DateScheduler) -> SignalProducer<Value, Error> {
precondition(count >= 0)

if count == 0 {
return producer
}

var retries = count

return flatMapError { error in
// The final attempt shouldn't defer the error if it fails
var producer = SignalProducer<Value, Error>(error: error)
if retries > 0 {
producer = SignalProducer.empty
.delay(interval, on: scheduler)
.concat(producer)
}

retries -= 1
return producer
}
.retry(upTo: count)
}

/// Wait for completion of `self`, *then* forward all events from
/// `replacement`. Any failure or interruption sent from `self` is
/// forwarded immediately, in which case `replacement` will not be started,
Expand Down
101 changes: 101 additions & 0 deletions Tests/ReactiveSwiftTests/SignalProducerSpec.swift
Expand Up @@ -1962,6 +1962,107 @@ class SignalProducerSpec: QuickSpec {
let result = producer.single()
expect(result?.value) == 1
}

context("with interval") {

it("should send values at the given interval") {

let scheduler = TestScheduler()
var count = 0

let original = SignalProducer<Int, TestError> { observer, _ in

if count < 2 {
scheduler.schedule { observer.send(value: count) }
scheduler.schedule { observer.send(error: .default) }
} else {
scheduler.schedule { observer.sendCompleted() }
}
count += 1
}

var values: [Int] = []
var completed = false

original.retry(upTo: Int.max, interval: 1, on: scheduler)
.start { event in
switch event {
case let .value(value):
values.append(value)
case .completed:
completed = true
default:
break
}
}

expect(count) == 1
expect(values) == []

scheduler.advance()
expect(count) == 1
expect(values) == [1]
expect(completed) == false

scheduler.advance(by: .seconds(1))
expect(count) == 2
expect(values) == [1, 2]
expect(completed) == false

scheduler.advance(by: .seconds(1))
expect(count) == 3
expect(values) == [1, 2]
expect(completed) == true
}

it("should not send values after hitting the limitation") {

let scheduler = TestScheduler()
var count = 0
var values: [Int] = []
var errors: [TestError] = []

let original = SignalProducer<Int, TestError> { observer, _ in
scheduler.schedule { observer.send(value: count) }
scheduler.schedule { observer.send(error: .default) }
count += 1
}

original.retry(upTo: 2, interval: 1, on: scheduler)
.start { event in
switch event {
case let .value(value):
values.append(value)
case let .failed(error):
errors.append(error)
default:
break
}
}

scheduler.advance()
expect(count) == 1
expect(values) == [1]
expect(errors) == []

scheduler.advance(by: .seconds(1))
expect(count) == 2
expect(values) == [1, 2]
expect(errors) == []

scheduler.advance(by: .seconds(1))
expect(count) == 3
expect(values) == [1, 2, 3]
expect(errors) == [.default]

scheduler.advance(by: .seconds(1))
expect(count) == 3
expect(values) == [1, 2, 3]
expect(errors) == [.default]
}

}

}

describe("then") {
Expand Down

0 comments on commit 4c0e12b

Please sign in to comment.