The backup requests pattern is a technique to deal e.g. with "long tail latencies". See e.g. https://www.typesafe.com/blog/reactive-revealed-part-1-of-3-async-nio-back-pressure-and-the-message-driven-vs-event-driven-approach (slide 77 and following) for an introduction.
How to implement this with RxJava?
-
In an existing classic, synchronous codebase… sometimes a call is "slow"
-
Solution: The relevant call (imagine calling a remote system) is wrapped with an rx.Observable and executed in a separate thread
-
Using the timer operator we setup a delayed backup call
-
Using the merge operator we merge the two observables
-
And the first operator emits the "faster" result and does the auto-unsubscribe resulting in cancelling the "slower" call
Warning:
-
This is a simplified solution
-
The problem is much more complicated in practice
-
When is the timeout due? Hardcoded values don’t fit well… You need something like e.g. a dynamically calculated 90th percentile
-
What if the second call is also slow?
-
What if the first call is answered just after the second call is issued? Would be nice to take that result and abort the second…
-
What if all calls are currently slow? You’ll need something like a circuit breaker…
-
You don’t want retry-storms. What about an exponential backoff retry strategy like https://github.com/Netflix/ocelli/blob/master/ocelli-core/src/main/java/netflix/ocelli/retrys/ExponentialBackoff.java
-
What if… (choose your own)
-
-
For more details see e.g. https://github.com/Netflix/ocelli, https://github.com/Netflix/Hystrix, Netflix/Hystrix#25, http://www.bailis.org/blog/doing-redundant-work-to-speed-up-distributed-queries