Async cleanup on observable sequence termination

Viewed 484

I need to execute an asynchronous method (e.g. a cleanup job) on an observable completion/failure. Also if the cleanup method fails the observable chain should also fail.

Is there a standard way of doing this?

Suppose I have a sequence Observable source and asyncCleanup() method that returns an observable cleanup result.

The side effect methods such as doOnCompleted/doOnTerminate/doOnUnsubscribe do not seem to be suitable:

source.doOnUnsubscribe(()->asyncCleanup().subscribe());

The observable chain will succeed even if asyncCleanup() fails. So asyncCleanup() should be a part of the same chain.

The best I came up with is the following:

source.onErrorResumeNext(err->asyncCleanup()
         .flatMap(cleanupResult->Observable.error(err)))
      .concatWith(asyncCleanup()
         .flatMap(cleanupResult->Observable.empty()));

In case of failure, onErrorResumeNext will call asyncCleanup() and will map back to to the original error. In case of success, we can concatenate with asyncCleanup() mapped to an empty sequence. Unfortunately, it is not going to work if there is a take() or similar limiting operator downstream, which may cause the concatenated observable not even subscribe.

UPDATE 2017-08-01: The question is specifically about sequence observables. For a single-item observable source the solution is quite simple:

singleItemSource
    .onErrorResumeNext(err->asyncCleanup()
        .flatMap(cleanupResult->Observable.error(err)))
    .flatMap(single->asyncCleanup()
        .map(cleanupResult->single));
3 Answers
Related