Skip to content

Commit 7cbe50f

Browse files
Fix shared state in retry (#829)
* Fix retry using shared state * update changelog * Update CHANGELOG.md * Add unit test Co-authored-by: Anders Ha <[email protected]>
1 parent 2ab421a commit 7cbe50f

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# master
22
*Please add new entries at the top.*
33

4+
1. Fixed issue where `SingalProducer.try(upTo:interval:count:)` shares state between invocation of `start` on the same producer.
5+
46
# 6.7.0
57
# 6.7.0-rc1
68

@@ -42,7 +44,6 @@
4244
1. Bumped deployment target to iOS 9.0, per Xcode 12 warnings. (#818, kudos to @harleyjcooper)
4345

4446
1. Fixed a few deprecation warning when the project is being built. (#819, kudos to @apps4everyone)
45-
>>>>>>> origin/master
4647

4748
# 6.5.0
4849

Sources/SignalProducer.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2393,9 +2393,10 @@ extension SignalProducer {
23932393
return producer
23942394
}
23952395

2396-
var retries = count
2396+
return SignalProducer { observer, lifetime in
2397+
var retries = count
23972398

2398-
return flatMapError { error -> SignalProducer<Value, Error> in
2399+
lifetime += flatMapError { error -> SignalProducer<Value, Error> in
23992400
// The final attempt shouldn't defer the error if it fails
24002401
var producer = SignalProducer<Value, Error>(error: error)
24012402
if retries > 0 {
@@ -2408,6 +2409,8 @@ extension SignalProducer {
24082409
return producer
24092410
}
24102411
.retry(upTo: count)
2412+
.start(observer)
2413+
}
24112414
}
24122415

24132416
/// Wait for completion of `self`, *then* forward all events from

Tests/ReactiveSwiftTests/SignalProducerSpec.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2812,6 +2812,40 @@ class SignalProducerSpec: QuickSpec {
28122812
expect(errors) == [.default]
28132813
}
28142814

2815+
it("should not share retry counter across produced signals") {
2816+
let scheduler = TestScheduler()
2817+
var failuresReceived = 0
2818+
2819+
let original = SignalProducer<Int, TestError> { observer, _ in
2820+
scheduler.schedule { observer.send(error: .default) }
2821+
}
2822+
let retryDelay: DispatchTimeInterval = .seconds(1)
2823+
let retriable = original
2824+
.retry(upTo: 1, interval: retryDelay.timeInterval, on: scheduler)
2825+
.on(failed: { _ in failuresReceived += 1 })
2826+
2827+
// 1st produced signal
2828+
retriable.start()
2829+
2830+
scheduler.advance()
2831+
expect(failuresReceived) == 0
2832+
2833+
scheduler.advance(by: retryDelay)
2834+
expect(failuresReceived) == 1
2835+
2836+
// 2nd produced signal
2837+
retriable.start()
2838+
2839+
scheduler.advance()
2840+
// Shared retry counter had caused the second produced signal not to defer the failed event as expected.
2841+
// (https://github.com/ReactiveCocoa/ReactiveSwift/pull/829)
2842+
// Assert that we did not receive the 2th final failure at this point, which should always be delayed until
2843+
// at least `retryDelay` has elapsed.
2844+
expect(failuresReceived) == 1
2845+
2846+
scheduler.advance(by: retryDelay)
2847+
expect(failuresReceived) == 2
2848+
}
28152849
}
28162850

28172851
}

0 commit comments

Comments
 (0)