I'm trying to construct a robust processing pipeline with rx-java but I ran into a problem.
Here is an example:
public static void main(String[] args) {
AtomicInteger div = new AtomicInteger(-1);
Observable.just(1, 1, 1).map(item -> 1 / div.getAndIncrement())
.retry().subscribe(item -> System.out.println(item));
}
The output in this case is 4 items, since the non-stream observable is replayed, but that's not relevant so just ignore it for the sake of simplicity. I've added comments that show the calculation to reach the result and the point of resubscribing:
-1 // 1 / -1
// 1/0 (error) - resubscribes to observable
1 // 1 / 1
0 // 1 / 2
0 // 1 / 3
This happens because the retry
operator (as all retry operators) causes a resubscribe once an error notification is passed.
My expected output would be:
-1 // 1 / -1
// 1/0 (error) - resubscribe but resume erroneous item (1)
1 // 1 / 1
0 // 1 / 0
When the error notification is passed, the re-subscribe process should include the erroneous item in the stream (retry on the same item) - since the error is external and not embedded in the processed item (so re-processing would make sense).
This is a case of some external error (like database connectivity) where I'd like the items that are not processed to be re-processed with some delay. I know that resubscribing is possible using the standard retry operators but all of them give up on the erroneous item.
I also thought about wrapping all my processing in try-catch where I suspect errors are possible but adds boilerplate code to my processing code and I prefer not to.
So my question is: Is there a standard way to retry on the item that failed?
I already thought about doing something like (not tested):
someSubject.flatMap(
item-> Observable.just(item)
.doOnError(err -> someSubject.onNext(item))).onErrorX...
And suppress errors...
But this seems unnatural and is expensive in my use case (Creating an observable for each item).
Is there an operator, or a combination of operators, that can cause retry to pass the erroneous item back to the beginning of the observable without "breaking" or wrapping the item in a different observable?
This is also the retry style I'm used to from using async-retry.