Netflix/RxJava — pull request #892 by benjchristensen (2014-02-17 23:32:46+00:00)
Title: onErrorFlatMap + OnErrorThrowable

I am working on solving a production error handling use case that needs the ability to handle errors on an `Observable` acting like a message-bus. This requires it to ignore errors if they occur.

With @headinthebox the idea of `onErrorFlatMap` evolved, but we now have a decision to make about the implementation.

It's pretty easy to solve the first half and allow `onErrorFlatMap` to return `Observables` that are injected into the output `Observable` but don't `onComplete` and thus allow the stream to continue.

However, we're looking at whether we can also capture the `T value` that caused the exception to be thrown so we can achieve use cases like this:

```java
@Test
public void spliceAndContinueEmitting() {
TestSubscriber ts = new TestSubscriber();
Observable.from(1, 2, 3, 4, 5, 6).map(new Func1() {

@Override
public String call(Integer v) {
if (v < 2 || v > 5) {
return "Value=" + v;
}
throw new RuntimeException("error in map function: " + v);
}

}).onErrorFlatMap(new Func1>() {

@Override
public Observable call(OnErrorThrowable t) {
return Observable.from("Error=" + t.getValue());
}

}).subscribe(ts);

ts.assertTerminalEvent();
System.out.println(ts.getOnErrorEvents());
assertEquals(0, ts.getOnErrorEvents().size());
System.out.println(ts.getOnNextEvents());
ts.assertReceivedOnNext(Arrays.asList("Value=1", "Error=2", "Error=3", "Error=4", "Error=5", "Value=6"));
}
```

This outputs:

```
[Value=1, Error=2, Error=3, Error=4, Error=5, Value=6]
```

To accomplish this however we must capture the `value` and wrap the `Throwable` in all operators that execute user-provided functions. This results in code like this:

```java
@Override
public void onNext(T t) {
try {
o.onNext(transformer.call(t));
} catch (Throwable e) {
onError(new OnErrorThrowable(e, t));
}
}
```

instead of this:

```java
@Override
public void onNext(T t) {
try {
o.onNext(transformer.call(t));
} catch (Throwable e) {
onError(e);
}
}
```

The drawback to this is that `onError` will now receive an `OnErrorThrowable` if the error comes from a user-provided function. The benefit is that the value associated with the failure is now accessible for debugging, reporting, feedback loops etc.

Operators affected by this are `cast`, `doOnEach`, `filter`, `groupBy`, `map`, `scan`, `zip` (and surely others) as these all take user-provided functions.

Are there reasons we should not wrap these errors inside an `OnErrorThrowable`?