I have a function capturing events from an api which works great. The only issue is i dont want the stream to be complete when it fails.
public func getDeviceEvent(deviceUID: String) -> SignalProducer<DeviceEvent, HTTPConnectorError> {
return SignalProducer<DeviceEvent, HTTPConnectorError> { observer, _ in
self.getDeviceEvent(deviceUID: deviceUID) { result in
switch result {
case .success(let deviceEvent):
observer.send(value: deviceEvent)
observer.sendCompleted()
case .failure(let error):
observer.send(error: error)
}
}
}
}
private func getDeviceEvent(deviceUID: String, completion: @escaping (Result<DeviceEvent, HTTPConnectorError>) -> Void) {
httpConnector.request(authenticated: true, target: .deviceLocationEvent(deviceID: deviceUID), parse: makeParser(), completion: completion)
}
Is there a way i can keep the stream going? i know there is retry
but i don't want to add a number of times i just want it to continue.
You could create your own version of retry
which retries indefinitely (I've included a version here that pauses for a given interval after each failure):
extension SignalProducer {
func retry() -> SignalProducer<Value, Never> {
flatMapError { _ in
self.retry()
}
}
func retry(interval: TimeInterval, on scheduler: DateScheduler) -> SignalProducer<Value, Never> {
flatMapError { _ in
SignalProducer<Value, Never>.empty
.delay(interval, on: scheduler)
.concat(self.retry(interval: interval, on: scheduler))
}
}
}
Then you can use on(failed:)
to display something to the user on each failure while retrying indefinitely:
getDeviceEvent(deviceUID: someDeviceUID)
.on(failed: { error in
print(error)
// Display this to the user
})
.retry(interval: 1.0, on: QueueScheduler())
.take(during: self.lifetime)
.startWithValues { value in
print(value)
}
This snippet assumes self
is a view controller; take(during: self.lifetime)
will then stop the operation when the current view controller deallocates. You ought to do something like this to prevent this retrying forever in the worst case.