Skip to content
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

Issues with RetryWhen #148

Open
Kn1kt opened this issue Nov 4, 2022 · 8 comments
Open

Issues with RetryWhen #148

Kn1kt opened this issue Nov 4, 2022 · 8 comments

Comments

@Kn1kt
Copy link

Kn1kt commented Nov 4, 2022

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()
}
@freak4pc
Copy link
Member

freak4pc commented Nov 4, 2022

Mind taking a look? @danielt1263

@danielt1263
Copy link
Contributor

I'll have a look this weekend.

@danielt1263
Copy link
Contributor

danielt1263 commented Nov 13, 2022

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

@Kn1kt
Copy link
Author

Kn1kt commented Nov 13, 2022

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

@BerkeleyTrue
Copy link

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

@emixb
Copy link
Contributor

emixb commented Mar 8, 2023

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

@doxuto
Copy link

doxuto commented Aug 28, 2024

@freak4pc Pls check @danielt1263 's PR. Thanks

@Kn1kt
Copy link
Author

Kn1kt commented Aug 31, 2024

Looks like this PR stuck. I have improved this operator, you can check out it here: CombineKit. Hope this helps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants