You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: Part 3 - Taming the sequence/3. Advanced error handling.md
+18-20Lines changed: 18 additions & 20 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# Advance error handling
2
2
3
-
We've already seen that we can handle an error in the observer. By that time, we are practically ourside of the monad. There can be many kinds of errors and not every error is worth pushing all the way to the top. In standard Java, you can catch an exception at any level and decide if you want to handle it there or throw it further. Similarily in Rx, you can define behaviour based on errors without killing your observable and forcing the observer to deal with everything.
3
+
We've already seen how we can handle an error in the observer. However, by that time, we are practically ourside of the monad. There can be many kinds of errors and not every error is worth pushing all the way to the top. In standard Java, you can catch an exception at any level and decide if you want to handle it there or throw it further. Similarily in Rx, you can define behaviour based on errors without terminating the observable and forcing the observer to deal with everything.
4
4
5
5
## Resume
6
6
@@ -32,7 +32,7 @@ Error: adjective unknown
32
32
33
33
### onErrorResumeNext
34
34
35
-
The `onErrorResumeNext` allows you to resume a failed sequence with another. The error will not appear in the resulting observable.
35
+
The `onErrorResumeNext` allows you to resume a failed sequence with another sequence. The error will not appear in the resulting observable.
36
36
37
37
```java
38
38
publicfinalObservable<T> onErrorResumeNext(
@@ -43,7 +43,7 @@ public final Observable<T> onErrorResumeNext(
The first overload uses the same followup observable in every case. The second overload allows you to decide what the resume sequence should be based on the error that was pushed
46
+
The first overload uses the same followup observable in every case. The second overload allows you to decide what the resume sequence should be based on the error that occured.
There's nothing stopping your resume sequence from failing as well. In fact, if you wanted to change the type of the error, you can return an observable that fails immediatelly. In standard Java, components may decide they can't handle an error and that they should re-throw it. They then may wrap new exceptions around the original error, to provide additional context. You can do the same in Rx:
67
+
There's nothing stopping the resumeSequence from failing as well. In fact, if you wanted to change the type of the error, you can return an observable that fails immediatelly. In standard Java, components may decide they can't handle an error and that they should re-throw it. In such cases, it is common wrap a new exception around the original error, thus providing additional context. You can do the same in Rx:
If the error doesn't go away, `retry()` will lock us in an infinite loop of retries. The second overload limits the number of retries. If the error persists, `retry(n)` will fail. Lets see this in an example
102
+
If the error doesn't go away, `retry()` will lock us in an infinite loop of retries. The second overload limits the number of retries. If errors persist and the sequence fails n times, `retry(n)` will fail too. Lets see this in an example
103
103
104
104
```java
105
105
Random random =newRandom();
@@ -124,21 +124,23 @@ java.lang.Exception
124
124
125
125
Here. we've specified that we want to retry once. Our observable fails after two values, then tries again, fails again. The second time it fails the exception is allowed through.
126
126
127
-
In this example, we have done something naughty: we have made our subscription stateful to demonstrate that the observable is restarted from the source. The observable produced different values the second time around. `retry` does not cache any elements like `replay`, nor would it make sense to do so. It will become apparent why this matters once we discuss the differences between hot and cold observables.
127
+
In this example, we have done something naughty: we have made our subscription stateful to demonstrate that the observable is restarted from the source: it produced different values the second time around. `retry` does not cache any elements like `replay`, nor would it make sense to do so. Retrying makes sense only if there are side effects, or if the observable is [hot](/Part%203%20-%20Taming%20the%20sequence/6.%20Hot%20and%20Cold%20observables.md).
128
128
129
129
### retryWhen
130
130
131
131
`retry` will restart the subscription as soon as the failure happens. If we need more control over this, we can use `retryWhen`.
132
132
133
133
```java
134
-
publicfinalObservable<T> retryWhen(Func1<? super Observable<? extends java.lang.Throwable>,? extends Observable<?>> notificationHandler)
134
+
publicfinalObservable<T> retryWhen(
135
+
Func1<? super Observable<? extends java.lang.Throwable>,? extends Observable<?>> notificationHandler)
135
136
```
136
137
137
138
The argument to `retryWhen` is a function that takes an observable and returns another. The input observable emits all the errors that `retryWhen` encounters. The resulting observable signals when to retry:
138
139
* if it emits a value, `retryWhen` will retry,
139
140
* if it terminates with error, `retryWhen` will emit the error and not retry.
140
-
* if it terminates successfully, `retryWhen` will terminate successfully
141
-
Note that the type of the signaling obserable of the actual values emitted don't matter. The values are discarded and the observable is only used for timing.
141
+
* if it terminates successfully, `retryWhen` will terminate successfully.
142
+
143
+
Note that the type of the signaling observable and the actual values emitted don't matter. The values are discarded and the observable is only used for timing.
142
144
143
145
In the next example, we will construct a retrying policy where we wait 100ms before retrying.
Our source observable emits 2 values and immediately fails. When that happens, the observable of failures inside `retryWhen` emits the error. We delay that emission by 100ms and send it back to signal a retry. `take(2)` guarantees that our signaling observabe will terminate after we receive two errors. That means that `retryWhen`won't retry after 2 failures. We concatenate an error to make `retryWhen` also fail.
172
+
Our source observable emits 2 values and immediately fails. When that happens, the observable of failures inside `retryWhen` emits the error. We delay that emission by 100ms and send it back to signal a retry. `take(2)` guarantees that our signaling observabe will terminate after we receive two errors. `retryWhen`sees the termination and doesn't retry after the second failures.
173
173
174
174
## using
175
175
176
-
The `using` operator is for creating observables from resources that need to managed. It guarantees that your resources will be managed regardless of when and how subscriptions are terminated. If you were to just use `create`, you would have to do the managing in the traditional Java paradigm and inject it into Rx. `using` is a more natural way of managing you resources in Rx.
176
+
The `using` operator is for creating observables from resources that need to managed. It guarantees that your resources will be managed regardless of when and how subscriptions are terminated. If you were to just use `create`, you would have to do the managing in the traditional Java paradigm and inject it into Rx. `using` is a more natural way of managing resources in Rx.
177
177
178
178
```java
179
179
publicstaticfinal<T,Resource>Observable<T> using(
@@ -223,11 +223,9 @@ e
223
223
Disposed: MyResource
224
224
```
225
225
226
-
When we subscribe to `values`, the resource factory function is called which returns the `"MyResource"`. That string is used to produce an observable which emits all of the characters in the string. Once the subscription ends, the string is disposed of.
227
-
228
-
It is important to note here that we are responsible for terminating the observable. Only then will the resources be released. If we had not called `o.onCompleted()`, the sequence would be assumed to be still active and needing its resources.
226
+
When we subscribe to `values`, the resource factory function is called which returns `"MyResource"`. That string is used to produce an observable which emits all of the characters in the string. Once the subscription ends, the resource is disposed of. A `String` doesn't need any more managing than what the garbage collector will do. Resources may actually need such managing include listening on ports, database connections, opened files etc.
229
227
230
-
A `String` doesn't need any more managing that what the garbage collector will do. `using` should be used for resources that are not released automatically, such as listening on ports, database connections, opening files etc.
228
+
It is important to note here that we are responsible for terminating the observable, just like we were when using the `create` method. With `create`, terminating is a matter of schemantics. With `using`, not terminating defeats the point of using it in the first place. Only upon termination will the resources be released. If we had not called `o.onCompleted()`, the sequence would be assumed to be still active and needing its resources.
0 commit comments