0

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.

Wazza
  • 1,725
  • 2
  • 17
  • 49

1 Answers1

1

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.

jjoelson
  • 5,771
  • 5
  • 31
  • 51