Skip to content

Proposal: Support for @RecoverableBean to allow graceful initialization failure #36670

@UsaidAijaz

Description

@UsaidAijaz

Problem to be solved

Currently, Spring Boot’s bean initialization process is strictly "fail-fast." If a @Bean factory method throws an exception during startup, the ApplicationContext fails to refresh, and the JVM shuts down.

While this is the correct behavior for critical infrastructure (e.g., a primary DataSource), it creates a single point of failure for non-critical peripheral services. In modern cloud-native environments, we often have beans that are "nice-to-have" but not mission-critical, such as:

  • Secondary telemetry/metrics exporters.
  • Third-party API clients used for non-essential features.
  • Local file-system watchers or specialized cache providers that might fail due to environmental misconfiguration.

Currently, to make these "optional" at startup, developers must either:

  1. Wrap the entire logic in every @Bean method with a try-catch and return null.
  2. Use @Lazy, which only delays the crash until runtime and prevents the use of Optional injection throughout the lifecycle.

Suggested Solution

Introduce a mechanism (potentially a new annotation like @Recoverable or an attribute on @Bean) that allows a bean to fail during initialization without stopping the application.

Example Usage:

@Bean
@Recoverable 
public NonCriticalService nonCriticalService() {
    // If this throws an exception (e.g., ConnectionRefused), the app starts anyway.
    return new NonCriticalService(); 
}

Proposed Behavior:

  • If the factory method throws an exception, Spring catches it, logs a WARN level message, and registers the bean as null (or an empty Optional).
  • Downstream beans can then inject this as Optional<NonCriticalService> to handle the absence of the service gracefully.
  • This ensures the failure is contained to the specific bean and its direct dependents, rather than crashing the whole system.

Why @Lazy is not a solution

  • Deferred Crashing: @Lazy moves the failure from startup to the first request. This makes production issues harder to debug and results in "zombie" services that stay alive but crash the moment they are actually used.
  • Proactive Validation: We want to attempt creation at startup to verify configuration. If it fails, we want to know immediately (via logs), but we want the core application to remain available.
  • Predictability: @Recoverable allows for a predictable "null" state throughout the application's life, whereas @Lazy leaves the application in an unstable state where any thread could trigger a fatal exception at any time.

Additional Context

By making this an "opt-in" feature, we preserve Spring's default fail-fast integrity while providing a declarative way to build more resilient, fault-tolerant applications. It eliminates the boilerplate of manual try-catch blocks and makes the developer's "resilience intent" explicit in the code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions