Failsafe policies determine which execution results or failures to handle and how to handle them. By default, policies handle any
Exception that is thrown. But policies can also be configured to handle more specific failures or conditions:
policy .handle(ConnectException.class, SocketException.class) .handleIf(failure -> failure instanceof ConnectException);
They can also be configured to handle specific results or result conditions:
policy .handleResult(null) .handleResultIf(result -> result == null);
When multiple handle methods are configured, they are logically OR’ed.
Policies can be composed in any way desired, including multiple policies of the same type. Policies handle execution results in reverse order, similar to the way that function composition works. For example, consider:
Failsafe.with(fallback, retryPolicy, circuitBreaker, timeout).get(supplier);
This results in the following internal composition when executing the
supplier and handling its result:
This means the
Supplier is evaluated first, then it’s result is handled by the
Timeout, then the
RetryPolicy, and the
Fallback. Each policy makes its own determination as to whether the result represents a failure. This allows different policies to be used for handling different types of failures.
A typical Failsafe configuration that uses multiple policies might place a
Fallback as the outer-most policy, followed by a
CircuitBreaker, and a
Timeout as the inner-most policy:
Failsafe.with(fallback, retryPolicy, circuitBreaker, timeout)
That said, it really depends on how the policies are being used, and different compositions make sense for different use cases.
Read about the built-in policies that Failsafe supports: