SmallRye Fault Tolerance 5.4

Today, we announce the release of SmallRye Fault Tolerance 5.4.0. This release includes several new features and fixes related to the programmatic API. It should be a safe upgrade for everyone using SmallRye Fault Tolerance 5.3.x.

Reusable, preconfigured fault tolerance strategies

In SmallRye Fault Tolerance 5.3.0, we introduced the programmatic API. In this release, we augment that with a declarative way of applying programmatically created fault tolerance! This allows centralizing fault tolerance configuration, as well as sharing fault tolerance state, all in a nice declarative fashion consistent with MicroProfile Fault Tolerance.

Let’s demonstrate it with an example. First, you have to create a bean of type FaultTolerance with an @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();
}

It is customary to create the bean by declaring a static producer field, which is what we’ve done here.

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() {
        ...
    }
}

See the documentation for more information.

Exception decisions in programmatic API

The circuit breaker, fallback, and retry fault tolerance strategies allow configuring what happens on certain exceptions. Both the declarative and programmatic API allow configuring a set of exception classes that are considered expected and unexpected.

With this release, the programmatic API also lets you supply a simple exception predicate, which allows expressing more complex exception decisions. For example:

Callable<String> guarded = FaultTolerance.createCallable(this::action)
        .withFallback().handler(this::fallback).when(e -> e instanceof RuntimeException).done()
        .build();

Of course, the value of this approach is that the predicate may be more complex than a simple instanceof check.

Support for Kotlin suspending functions

SmallRye Fault Tolerance already supports some asynchronous types on top of the CompletionStage type mandated by the MicroProfile Fault Tolerance specification. Specifically, there’s support for Mutiny and RxJava 3 and more could easily be added if needed.

In this release of SmallRye Fault Tolerance, a new module smallrye-fault-tolerance-kotlin is added that provides support for Kotlin suspend functions. They are also considered asynchronous, so fault tolerance applies across suspension points, like you’d expect.

For example:

@ApplicationScoped
open class MyService {
    @Retry(maxRetries = 2)
    @Fallback(fallbackMethod = "helloFallback")
    open suspend fun hello(): String {
        delay(100)
        throw IllegalArgumentException()
    }

    private suspend fun helloFallback(): String {
        delay(100)
        return "hello"
    }
}

Others

The SmallRye Fault Tolerance documentation of the programmatic API recommends to store FaultTolerance instances into static fields. This has some interesting implications. Specifically, the entire fault tolerance chain is built in the static initializer, and that includes looking up several beans from the CDI container and possibly even creating a thread. That is problematic in Quarkus when compiling to a native image, because static initialization code is executed during native image build.

In this release of SmallRye Fault Tolerance, this problem is fixed. Almost all of the initialization is deferred to runtime.

All in all, upgrading to 5.4.0 is very much recommended. As described above, there are certain new things, so if you encounter any bugs, please let us know in the issue tracker! We’re still very much interested in any feedback on the programmatic API.