CombineExt icon indicating copy to clipboard operation
CombineExt copied to clipboard

Issues with RetryWhen

Open Kn1kt opened this issue 2 years ago • 8 comments

Now RetryWhen subscribes to upstream twice. This is because the Sink itself subscribes to the upstream in .init. Test testSuccessfulRetry() checks the number of subscriptions, but not correctly. It should check that the error publisher produces at least one item.

The correct test should look like this:

func testSuccessfulRetry() {
        var times = 0
        var retriesCount = 0
        
        var expectedOutput: Int?
        
        var completion: Subscribers.Completion<RetryWhenTests.MyError>?

        subscription = Deferred(createPublisher: { () -> AnyPublisher<Int, MyError> in
            defer { times += 1 }
            if times == 0 {
                return Fail<Int, MyError>(error: MyError.someError).eraseToAnyPublisher()
            }
            else {
                return Just(5).setFailureType(to: MyError.self).eraseToAnyPublisher()
            }
        })
        .retryWhen { error in
            error
                .handleEvents(receiveOutput: { _ in retriesCount += 1})
                .map { _ in }
        }
        .sink(
            receiveCompletion: { completion = $0 },
            receiveValue: { expectedOutput = $0 }
        )

        XCTAssertEqual(
            expectedOutput,
            5
        )
        XCTAssertEqual(completion, .finished)
        XCTAssertEqual(times, 2)
        XCTAssertEqual(retriesCount, 1)
    }

A possible solution is to remove upstream subscription from Sink.init and setting upstreamIsCancelled cancelUpstream function.

private let lock = NSRecursiveLock()


/// ...

func cancelUpstream() {
    lock.lock()
    guard !upstreamIsCancelled else {
        lock.unlock()
        return
    }
    upstreamIsCancelled = true
    lock.unlock()
    
    upstreamSubscription.kill()
}

Kn1kt avatar Nov 04 '22 17:11 Kn1kt

Mind taking a look? @danielt1263

freak4pc avatar Nov 04 '22 17:11 freak4pc

I'll have a look this weekend.

danielt1263 avatar Nov 04 '22 20:11 danielt1263

Good catch @Kn1kt. I have updated the test based on your suggestion and updated the code to make the test pass while still passing the other tests. See PR #150

danielt1263 avatar Nov 13 '22 20:11 danielt1263

Good job. I also made a couple of fixes that can be merged after your PR. #151

Kn1kt avatar Nov 13 '22 22:11 Kn1kt

Just had this bite me in the rear with API requests. @danielt1263 's PR fixed my issue.

BerkeleyTrue avatar Feb 23 '23 22:02 BerkeleyTrue

I also spent some time debugging this issue, can we merge @danielt1263's PR? Thanks!

emixb avatar Mar 08 '23 15:03 emixb