Thomvis/BrightFutures

Infinite loop with `recoverWith`

Closed this issue · 2 comments

I don't know what exactly is going on, and my research hit a wall:

I have the following piece of code:

        let locationInHubFuture = self.getUserLocationAndConfirmInHub()
            .recoverWith { [weak self] error -> Future<EndRentalLocation, CheckoutError> in
                //TODO: BUG!! called twice for some reasonm
                guard let strongSelf = self else { return Future(error: error) }
                switch error {
                case let .locationInAlternativeHubNoFlex(location: location):
                    //TESTCODE
//                    return Future(error: CheckoutError.locationTooFarFromHub)
                    //TESTCODE
                    return strongSelf
                        .presentUpgradeToFlexView()
                        .promoteError()
                        .flatMap{ upgradeFlexFinishedState -> Future<EndRentalLocation, CheckoutError> in
                            switch upgradeFlexFinishedState {
                            case UpgradeFlexFinishedState.upgradedToFlex: return Future(value: location)
                            case UpgradeFlexFinishedState.cancelled: return Future(error: CheckoutError.locationTooFarFromHub)
                            }
                    }

                default: return Future(error: error)
                }
        }

If the test code is enable, it does what I expect, which is to fail to recover. if however I use the current code, which present a VC and complete a future with the same value CheckoutError.locationTooFarFromHub It goes into an infinite loop where the recoverWith is called again and again.

    func presentUpgradeToFlexView() -> Future<UpgradeFlexFinishedState, NoError> {
        let rentalID = rental.rentalId
        let flexPriceFormatted = rental.booking.hub.flexPriceFormatted
        let hubName = rental.booking.hub.name

        let attachableVM = Attachable<EndRentalFlexUpgradeViewModel>.detached(dependencies: EndRentalFlexUpgradeViewModel.Dependencies(rentalID: rentalID, flexPriceFormatted: flexPriceFormatted, primaryHubName: hubName))
        let vc = EndRentalFlexUpgradeViewController.instantiate(vm: attachableVM, delegate: self)
        self.present(vc, animated: false, completion: nil)
        self.didUpgradeFlexPromise = Promise()

        return self.didUpgradeFlexPromise!
            .future
            .onComplete { [weak self] _ in
                self?.didUpgradeFlexPromise = nil
                self?.dismiss(animated: false, completion: nil)
        }
    }

    func endRentalFlexUpgradeViewController(_ controller: EndRentalFlexUpgradeViewController, didFinishWith state: UpgradeFlexFinishedState) {
        self.didUpgradeFlexPromise?.trySuccess(state)
    }

This is the rest of the code. I don't understand what's the difference, or why this is causing an infinite loop only in case I return the future error this way. Do you have any idea? have you ran into this issue?

Sorry to hear you're having an issue with BrightFutures.

It's kind of hard to see for me, without being able to compile & run the code. My first guess would be that invoking presentUpgradeToFlexView() somehow also causes the code in your first snippet to call again. That would mean that the recursive loop is not contained to within recoverWith, but is caused by an (indirect) recursive call in your code. Can you put a breakpoint on the following line

let locationInHubFuture = self.getUserLocationAndConfirmInHub()

or inside getUserLocationAndConfirmInHub to see if that gets called again too and by what.

Hope this helps!

Haha I totally tunneled visioned on the futures and async code that I forgot I'm calling this code in view will appear 🙈🙉 sorry.