# Migrating from Developing Asynchronous Multi-Threading Programs to Reactive Programs in Java
## 6 Implementation Details
### Handling System Errors  
Software systems are prone to unpredictable behavior and errors, but maintaining resilience and reliability is not possible without effective management. There are several strategies for handling exceptional cases, and implementation methods are also different depending on the paradigm. The standard approach implies the provision of a mechanism for computing an alternate response or an error handler that can vary in complexity, used at the moment when the application encounters the exceptional case. While this addresses the punctual error and provides a degree of control over the execution flow, it does not deal with the root cause and does not facilitate the recovery of the system from its unstable state. _CompletableFuture_ provides the _exceptionally_ method for handling errors in asynchronous operations, while _Mono_ and _Flux_ provide equivalent methods for handling errors in reactive flows, such as _onErrorResume_. If the primary process fails, a default value can be returned or an attempt can be made to retrieve the data from alternate sources. For example, in the scenario where the _getFollowedIds_ method fails, the data available in the cache is inspected by calling the _getFollowedUsersFromCache_ method. This approach can be further extended by executing the operations or streams that provide access to the same required data in parallel, e.g., a simultaneous database and cache lookup, instead of waiting for the regular version to fail. _CompletableFuture's anyOf_ method allows asynchronous operations to be launched simultaneously, with the result being determined by the first completed operation, while the _firstWithValue_ method provided in the reactive context waits for the first successful response, ignoring the failed ones. Occasionally, the errors encountered in applications may be temporary or non-deterministic, caused by fluctuating conditions. In such situations, retrying the operations is an elegant and practical solution for dealing with exceptional cases without requiring the development of specific and complex solutions. The asynchronous specification does not provide any implementation for retrying failed operations, requiring a programmatic solution such as recursion or the utilization of existing framework implementations such as Spring _Retry_. Instead, the _retry_ operator is available in the reactive context, which allows for detailed configuration by specifying the number of retries, timing strategy, and re-execution conditions for the operation. However, a more robust approach for dealing with errors in unpredictable situations, such as a sudden spike in traffic, is to leverage the \"Circuit Breaker\" pattern [60], which is designed to detect problems in real time and prevent errors from propagating throughout the system. A fallback method is configured, and when the main component becomes non-functional, resulting in the number of errors increasing, automatic redirection of requests to the fallback method takes place, ensuring a minimum level of operation and avoiding a total system outage. Periodically, an attempt will be made to gradually restore traffic through the main flow, and once the errors have completely disappeared, the fallback method is no longer invoked, and the system returns to normal operating conditions. The Resilience4j library provides versions compatible with both variants [61]. Listing 1 illustrates an example of using a _CircuitBreaker_ in the reactive application.