Press "Enter" to skip to content

RxJava Operators – Part 6: Timeout Operator

0

When developing an app, specially if we are dealing with requests to network resources, we might want to configure some timeouts, so if the server takes so long to process a request, we can take specific actions, instead of hang forever. RxJava provides an operator called timeout that, according to the docs, “allows you to abort an Observable with an onError termination if that Observable fails to emit any items during a specified span of time”. Although it is only one operator, there are some variants which can handle most (if not all) cases we may need.

This article will present six variants of timeout operators. As usual, you can find here a demo app that implements all examples demonstrated on this article.

Please, check below the previous articles of this series:

timeout() Operator with a Duration

Basically this variant applies a timeout policy for each emitted item. If the next item is not emitted within the duration informed in the parameter, it terminates with a TimeoutException.

In this example emitItems(N) method will emit 20 items by using a random delay from 100ms to 700ms between each item. Since we are using 500ms as a timeout, if source Observable takes more than that to emit an item, timeout operator will terminate with an error.

timeout() Operator with a Second Observable

There might be cases where, instead of terminate with an error when source does not emit any item within the specified timeout, we want to fallback to another Observable. If that is the case, timeout operator has a variant that accepts a second Observable which is emitted in case of the first one times out.

This example will trigger a second observable (i.e.: emitSecondItems method) if the first one takes more than 500ms to emit an item. Note that even if a timeout occurs in the first Observable, chain will not finish with any error, but keep processing items emitted from the second Observable instead.

Using this approach, we could, for example, request data from an external server, and in case it does not respond within a specified timeout, fallback to another server (of course this would involve a more complex chain of operators, but this is just to give an idea of a real use).

timeout() Operator with Function

If we need to apply different timeouts for each emitted items, we can use a variant that accepts a function. Basically this variant gives us a chance to examine each emitted item and define  different timeouts based on them.

This example checks every emitted items, and for even numbers it sets a timeout of 300ms, otherwise timeout is set to 600ms.

timeout() Operator with a Function and a Second Observable

If we need to apply different timeouts for each emitted items (as we did in the previous example), but instead of terminate with an error in case of a timeout, we also want to fallback to another Observable, timeout operator offers a variant to do it. This is basically a combination of the two previous examples:

On this example, in case of a timeout occurs on any emitted item (remember we are using different timeouts based on whether emitted items are even or not), a second observable is triggered (emitSecondItems method). Simple like that.

timeout() Operator with Different Functions

timeout() operator also offers a variant which we can define a function that is applied only for the first emitted item and another one applied to all the other items. This is useful when we have an overhead only for the first item (e.g.: a handshake while connecting to a resource). Then, we can set an appropriate timeout only for the first item, and different timeouts for all the other emitted items.

This example applies a function which defines a 500ms timeout only for the first emitted item. For all the others, it applies a second function that defines a 300ms of timeout for even numbers and 600ms for odd ones).

Putting all Together

Now, let’s see a variant which combines all the things we’ve seen so far: a function applied only for the first emitted item, a function for all the other items and a second observable to switch in case of timeout for any emitted item afterwards.

Similar to the previous example, this one applies a function which defines a 500ms timeout only for the first emitted item. Then a timeout of 300ms is applied for even numbers and 600ms for the odd ones. The difference is that on this example a second Observable is triggered in case of a timeout occurs in the first Observable.

Bonus Example

Now, let’s present a (little) more complex example. If source observable takes more than 500ms to emit an item, timeout operator will emit an error. Whenever it happens, retryWhen() is called and delays five seconds prior to emit. In case of it reaches the maximum number of attempts (i.e.: 3 times), it will emit an error and the whole chain terminates with an error.

Conclusion

As we demonstrated, timeout() operator provides many variants. By combining them with other operators, we can build up powerful chains that can fit in most (if not all) cases we might need. We mentioned before they are useful especially when querying data from the network, but of course they can be used for any kind of resource (e.g.: a database query, etc)

As usual, if you have questions, just leave a comment below.