This post has been republished via RSS; it originally appeared at: Android@Microsoft - Medium.
In the world of distributed systems and micro-services resiliency is an important concept that helps with building fault tolerant systems. In the Java world, Netflix has pioneered in this space with Hystrix, which is now in maintenance mode, and instead resilience4j is the recommended framework to use. And while these tools are very popular and powerful, I’ve never seen them being used in an Android context until recently.
While working on connectivity for Microsoft’s Your Phone app, we determined that having a resiliency framework will make it significantly easier to have fault tolerance. Consider the following example: You link your Android phone to your PC and are looking at your phone’s pictures from the PC when your phone suddenly loses its internet connection. Ideally, the phone and PC will now try to reconnect automatically and resume the session and this way recover gracefully from connectivity issues. In fact, it is the right thing to do from a UX perspective. We want to give the user the feeling that their devices are always connected or at-least trying their best to be connected. So how did we go about this?
Given that the Your Phone app consists of a UWP app for Windows and an Android app, we had to look at solutions for both platforms. On the Windows side, things were really easy because we could simply use the popular Polly framework, which can be used like this:
The great thing about Polly and C# is that for asynchronous code we can simply use the async/await mechanism which is fully supported by Polly and makes it very effortless to write resilient code for both synchronous and asynchronous operations. But what about Android?
For Android and Java things are a lot harder due to Java’s lack of a built-in concurrency framework and the resulting framework fragmentation, as well as Android’s (up until recently) lacking support for Java 8’s functional constructs. For instance, resilience4j is designed for Java 8 and functional programming and therefore requires JDK8 to be used. This obviously wasn’t possible on Android up until recently when core library desugaring became stable. At the same time our application does not use a single concurrency framework, we use both RxJava and a CompletableFuture backport. For this reason we ended up building our own minimalist resiliency framework that supports both Retry and CircuitBreaker for RxJava using custom operators.
If we had to start from scratch again today, it would probably be wise to use resilience4j by enabling core library desugaring. The great thing about the framework is that it comes with adapters for commonly used frameworks, including CompletableFuture (default), RxJava 2 and 3 and Kotlin coroutines and flow. Let’s look at a simple example to explore how easy it can be to write resilient code using Kotlin’s coroutines and Resilience4j. Let’s assume that we have a (very simplified) class that represents a connection between two devices and looks like this:
We will design a wrapper around this class that attempts to send a message to a device by first attempting to establish a connection and if successful, sending a message. The difficult part about this is that we have to assume that both operations can easily fail and therefore resiliency is key. Let’s first look at how we can define the retries using resilience4j:
We can simply define two retry strategies using the handy DSL that the Kotlin extension provides. For connecting to the device we will use an enum to represent the result of that operation and will retry if the remote device is unreachable using a delay of 3s between each try. For sending a message, we will make a total of 3 attempts with an exponential back off if we encounter a FailedToSendException. Resilience4j offers a rich API for defining Retries, CircuitBreakers, Bulkheads, Ratelimiters, Caches and more. To use a Retry, the library provides extension functions that allow us to compose the whole operation like so:
While this is a very simple example it shows how we can use the abstractions provided by Resilience4j to build powerful, fault tolerant code. The great thing about this framework is that it’s extremely flexible and comes with adapters for the most commonly used concurrency frameworks or we could even build an adapter for our own concurrency framework.
While not every app will equally benefit from adding resiliency mechanisms like this, frameworks like Resilience4j can make it extremely simple to make our code more fault tolerant without adding too much overhead. Especially when throwing Kotlin in the mix, adding resiliency can be as simple as calling an extension function and passing in an existing suspend function.
If you haven’t tried the Your Phone app, I can highly recommend to download it to connect your Android phone to your Windows computer: