7.3.7 Client Fallbacks
In distributed systems, failure happens and it is best to be prepared for it and handle it gracefully.
In addition, when developing Microservices it is quite common to work on a single Microservice without other Microservices the project requires being available.
With that in mind, Micronaut features a native fallback mechanism that is integrated into Retry Advice that allows falling back to another implementation in the case of failure.
Using the @Fallback annotation, you can declare a fallback implementation of a client to be used when all possible retries have been exhausted.
In fact the mechanism is not strictly linked to Retry; you can declare any class as @Recoverable, and if a method call fails (or, in the case of reactive types, an error is emitted) a class annotated with @Fallback
will be searched for.
To illustrate this, consider again the PetOperations
interface declared earlier. You can define a PetFallback
class that will be called in the case of failure:
Defining a Fallback
@Fallback
public class PetFallback implements PetOperations {
@Override
@SingleResult
public Publisher<Pet> save(String name, int age) {
Pet pet = new Pet();
pet.setAge(age);
pet.setName(name);
return Mono.just(pet);
}
}
Defining a Fallback
@Fallback
class PetFallback implements PetOperations {
@Override
Mono<Pet> save(String name, int age) {
Pet pet = new Pet(age: age, name: name)
return Mono.just(pet)
}
}
Defining a Fallback
@Fallback
open class PetFallback : PetOperations {
override fun save(name: String, age: Int): Mono<Pet> {
val pet = Pet()
pet.age = age
pet.name = name
return Mono.just(pet)
}
}
If you only need fallbacks to help with testing against external Microservices, you can define fallbacks in the src/test/java directory so they are not included in production code. You will have to specify @Recoverable(api = PetOperations.class) on the declarative client if you are using fallbacks without hystrix. |
As you can see the fallback does not perform any network operations and is quite simple, hence will provide a successful result in the case of an external system being down.
Of course, the actual behaviour of the fallback is up to you. You can for example implement a fallback that pulls data from a local cache when real data is not available, and sends alert emails or other notifications to operations about downtime.