Infinite loop with `recoverWith`
yoavschwartz opened 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.