Reusable Fault Tolerance
This is an additional feature of SmallRye Fault Tolerance and is not specified by MicroProfile Fault Tolerance. |
The declarative, annotation-based API of MicroProfile Fault Tolerance doesn’t allow sharing configuration of fault tolerance strategies across multiple classes. In a single class, the configuration may be shared across all methods by putting the annotations on the class instead of individual methods, but even then, stateful fault tolerance strategies are not shared. Each method has its own bulkhead, circuit breaker and/or rate limit, which is often not what you want.
The programmatic API of SmallRye Fault Tolerance allows using a single FaultTolerance
object to guard multiple disparate actions, which allows reuse and state sharing.
It is possible to use a programmatically constructed FaultTolerance
object declaratively, using the @ApplyFaultTolerance
annotation.
To be able to do that, we need a bean of type FaultTolerance
with the @Identifier
qualifier:
@ApplicationScoped
public class PreconfiguredFaultTolerance {
@Produces
@Identifier("my-fault-tolerance")
public static final FaultTolerance<String> FT = FaultTolerance.<String>create()
.withRetry().maxRetries(2).done()
.withFallback().handler(() -> "fallback").done()
.build();
}
See the programmatic API documentation for more information about creating the FaultTolerance
instance.
It is customary to create the bean by declaring a static
producer field, just like in the previous example.
Once we have that, we can apply my-fault-tolerance
to synchronous methods that return String
:
@ApplicationScoped
public class MyService {
@ApplyFaultTolerance("my-fault-tolerance")
public String doSomething() {
...
}
}
It is also possible to create a bean of type FaultTolerance<Object>
and apply it to synchronous methods that return different types.
Note that this effectively precludes defining a useful fallback, because fallback can only be defined when the value type is known.
It is also possible to define a bean of type FaultTolerance<CompletionStage<T>>
and apply it to asynchronous methods that return CompletionStage<T>
.
Likewise, it is possible to do this for additional asynchronous types.
Note that you can’t define a synchronous FaultTolerance<T>
object and apply it to any asynchronous method.
Similarly, you can’t define an asynchronous FaultTolerance<CompletionStage<T>>
and apply it to a synchronous method or an asynchronous method with different asynchronous type.
This limitation will be lifted in the future.
Metrics
Methods annotated @ApplyFaultTolerance
gather metrics similarly to methods annotated with MicroProfile Fault Tolerance annotations.
That is, each method gets its own metrics, with the method
tag being <fully qualified class name>.<method name>
.
At the same time, state is still shared.
All methods annotated @ApplyFaultTolerance
share the same bulkhead, circuit breaker and/or rate limit.
If the FaultTolerance
object used for @ApplyFaultTolerance
is also used programmatically, that usage is coalesced in metrics under the description as the method
tag.