Class FailoverAutoConfiguration
Activates when failover.enabled=true (the default). Registers all core
failover infrastructure beans: AOP aspect, expiry policy, key generators, payload
enricher, recovered-payload handler, method-exception policy, schedulers, and the
in-memory store factory (when no other store type is configured).
Store-type-specific beans (Caffeine, JDBC) and the final assembled FailoverStore
bean are produced by FailoverStoreAutoConfiguration (with per-tenant routing layered on
by FailoverStoreMultiTenantAutoConfiguration when enabled).
Note on structure: the core beans are declared flat on this class (rather
than grouped into nested @Configuration classes) on purpose. @ConditionalOnMissingBean
relies on auto-configuration ordering to let a user-declared bean win; nested @Configuration
classes lose that deferred ordering and break bean-override (the framework's primary extension
point). Keep new beans flat here unless they have no @ConditionalOnMissingBean.
- Author:
- Anand Manissery
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptioncompositeObservablePublisher(List<ObservablePublisher> observablePublishers, FailoverClock clock) Registers a composite publisher that stamps the publish timestamp once and broadcasts to everyObservablePublisherin the context.contextPropagator(List<ContextPropagator> contextPropagators) Composes the activeContextPropagatorfrom everyContextPropagatorbean in the application context, plus an always-onMdcContextPropagator: AllContextPropagatorbeans, gathered inorderedform.defaultExpiryPolicy(FailoverClock clock, FailoverExpiryExtractor failoverExpiryExtractor) Creates the default expiry policy bean.Creates the default key generator bean.Creates the expiry-policy lookup bean.failoverAspect(FailoverExecution<Object> failoverExecution) Registers the AOP aspect that intercepts@Failover-annotated methods.io.micrometer.core.instrument.config.MeterFilterfailoverCardinalityMeterFilter(FailoverProperties properties) Cardinality guard for thefailover.*meters: caps the number of distinctnametag values, denying further new series once the cap is hit so a misconfigured high-cardinality failover name can never explode the registry.Creates the default failover clock bean.failoverExecution(FailoverHandler<Object> failoverHandler, MethodExceptionHandler methodExceptionHandler, org.springframework.context.ApplicationContext applicationContext) RegistersBasicFailoverExecution, active whenfailover.type=basic(the default).Creates the failover expiry extractor bean.failoverExpiryPolicy(ExpiryPolicy<Object> defaultExpiryPolicy, ExpiryPolicyLookup<Object> expiryPolicyLookup) Creates the composite failover expiry policy.failoverHandler(KeyGenerator keyGenerator, ExpiryPolicy<Object> expiryPolicy, FailoverClock clock, FailoverStore<Object> failoverStore, PayloadEnricher<Object> payloadEnricher, RecoveredPayloadHandler recoveredPayloadHandler, org.springframework.context.ApplicationContext applicationContext, FailoverExpiryExtractor failoverExpiryExtractor, PayloadSplitterLookup<Object, Object> payloadSplitterLookup, ContextPropagator contextPropagator, org.springframework.beans.factory.ObjectProvider<org.springframework.core.task.TaskExecutor> scatterGatherExecutorProvider, FailoverProperties failoverProperties) Assembles the fullFailoverHandlerdecorator chain:AdvancedFailoverHandler(ScatterGatherFailoverHandler(DefaultFailoverHandler)).failoverKeyGenerator(KeyGenerator defaultKeyGenerator, KeyGeneratorLookup keyGeneratorLookup) Creates the composite failover key generator.io.micrometer.core.instrument.binder.MeterBinderfailoverMetricsDroppedMeterBinder(org.springframework.context.ApplicationContext applicationContext) Exposesfailover.metrics.dropped.totalwhen async publishing is active, so any metric dropped by a full queue is observable rather than silent.failoverObservablePublisher(CompositeObservablePublisher composite, FailoverProperties properties) The dispatching publisher used by the failover handler and the startup observer — wrapping theCompositeObservablePublisherin anAsyncObservablePublisherso metric publishing can never block or slow the caller's@Failovercall (the core observability contract).failoverObserver(CompositeObservablePublisher observablePublisher, FailoverScanner failoverScanner, FailoverClock clock, ManifestInfoExtractor manifestInfoExtractor, FailoverExpiryExtractor failoverExpiryExtractor, FailoverProperties failoverProperties) Creates the failover reporter bean that publishes a startup summary.Registers a Spring-native scanner that locates all@Failover-annotated methods by walking the already-builtApplicationContext.failoverStartupSummaryLogger(FailoverProperties properties, org.springframework.context.ApplicationContext applicationContext, org.springframework.beans.factory.ObjectProvider<FailoverScanner> scannerProvider) Logs a single consolidated startup summary covering infrastructure configuration and all discovered@Failoverendpoints.Creates the key-generator lookup bean.Registers aObservablePublisherthat writes failover reports to SLF4J.manifestInfoExtractor(ResourceLoader resourceLoader) Registers a caching manifest extractor for reading build metadata fromMANIFEST.MF.methodExceptionHandler(MethodExceptionPolicy methodExceptionPolicy) Registers theMethodExceptionHandlerthat applies the active exception policy.Creates the default payload enricher bean.Creates the payload-splitter lookup bean.Registers the default no-opRecoveredPayloadHandlerthat returns the payload unchanged.Registers a resource loader for reading classpath resources (e.g.org.springframework.core.task.TaskExecutorscatterGatherExecutor(FailoverProperties properties) Virtual-thread executor for parallel slice dispatch in scatter/gather operations.
-
Constructor Details
-
FailoverAutoConfiguration
public FailoverAutoConfiguration()
-
-
Method Details
-
failoverClock
Creates the default failover clock bean.- Returns:
- default
DefaultFailoverClock
-
defaultKeyGenerator
@ConditionalOnMissingBean(name="defaultKeyGenerator") @Bean(name="defaultKeyGenerator") public KeyGenerator defaultKeyGenerator()Creates the default key generator bean.- Returns:
DefaultKeyGenerator, which derives the key by joining the method arguments' string representations (seeDefaultKeyGeneratorfor the per-argument rules)
-
keyGeneratorLookup
Creates the key-generator lookup bean.- Returns:
BeanFactoryKeyGeneratorLookupresolving named key-generator beans
-
failoverKeyGenerator
@ConditionalOnMissingBean(name="failoverKeyGenerator") @Bean(name="failoverKeyGenerator") public KeyGenerator failoverKeyGenerator(@Qualifier("defaultKeyGenerator") KeyGenerator defaultKeyGenerator, KeyGeneratorLookup keyGeneratorLookup) Creates the composite failover key generator.- Parameters:
defaultKeyGenerator- fallback key generator when no named override is foundkeyGeneratorLookup- lookup that resolves per-@Failovernamed key generators- Returns:
- composite
FailoverKeyGeneratorthat delegates to named generators or the default
-
failoverExpiryExtractor
Creates the failover expiry extractor bean.- Returns:
BeanFactoryFailoverExpiryExtractorresolving named expiry-policy beans
-
defaultExpiryPolicy
@ConditionalOnMissingBean(name="defaultExpiryPolicy") @Bean public ExpiryPolicy<Object> defaultExpiryPolicy(FailoverClock clock, FailoverExpiryExtractor failoverExpiryExtractor) Creates the default expiry policy bean.- Parameters:
clock- clock used to compute expiry timestampsfailoverExpiryExtractor- extractor that reads expiry duration from@Failover- Returns:
- default expiry policy based on the annotation's configured duration
-
expiryPolicyLookup
Creates the expiry-policy lookup bean.- Returns:
BeanFactoryExpiryPolicyLookupresolving named expiry-policy beans
-
failoverExpiryPolicy
@ConditionalOnMissingBean(name="failoverExpiryPolicy") @Bean(name="failoverExpiryPolicy") public ExpiryPolicy<Object> failoverExpiryPolicy(@Qualifier("defaultExpiryPolicy") ExpiryPolicy<Object> defaultExpiryPolicy, ExpiryPolicyLookup<Object> expiryPolicyLookup) Creates the composite failover expiry policy.- Parameters:
defaultExpiryPolicy- fallback expiry policy when no named override is foundexpiryPolicyLookup- lookup that resolves per-@Failovernamed expiry policies- Returns:
- composite expiry policy that delegates to named policies or the default
-
payloadEnricher
Creates the default payload enricher bean.- Returns:
- default pass-through
DefaultPayloadEnricher
-
payloadSplitterLookup
Creates the payload-splitter lookup bean.- Returns:
BeanFactoryPayloadSplitterLookupresolving named splitter beans
-
contextPropagator
@ConditionalOnMissingBean(name="contextPropagator") @Bean public ContextPropagator contextPropagator(List<ContextPropagator> contextPropagators) Composes the activeContextPropagatorfrom everyContextPropagatorbean in the application context, plus an always-onMdcContextPropagator:- All
ContextPropagatorbeans, gathered inorderedform. This includes the auto-configuredTenantContextPropagator(whenfailover.store.multitenant.enabled=true) andMicrometerContextPropagator(whenio.micrometer.tracing.Traceris on the classpath and aTracerbean exists), and any customContextPropagatorbean you declare. Annotate a custom bean with@Orderto control its position in the chain. MdcContextPropagator— always appended last (innermost: restored immediately before the slice runs).
contextPropagatorto replace this composition entirely; declare any otherContextPropagatorbean to add it to the chain.The parameter is a
List(not anObjectProvider) on purpose: Spring's collection injection excludes the bean currently in creation, so thiscontextPropagatorbean does not gather itself (which would be a self-referentialBeanCurrentlyInCreationException). The list is ordered by@Order/Ordered.- Parameters:
contextPropagators- allContextPropagatorbeans in the context (self excluded),@Order-sorted- Returns:
- a single propagator or a
CompositeContextPropagatorwhen multiple are present
- All
-
scatterGatherExecutor
@ConditionalOnMissingBean(name="scatterGatherExecutor") @ConditionalOnProperty(prefix="failover.scatter", name="parallel", havingValue="true") @Bean(name="scatterGatherExecutor") public org.springframework.core.task.TaskExecutor scatterGatherExecutor(FailoverProperties properties) Virtual-thread executor for parallel slice dispatch in scatter/gather operations. Activated only whenfailover.scatter.parallel=true.Override by declaring a bean named
scatterGatherExecutor.Unbounded by default. When
failover.scatter.concurrency-limit > 0the virtual-thread executor is wrapped in aBoundedTaskExecutorthat caps concurrent slice fan-out and applies the configuredrejection-policyon overload (audit R-2); accepted slices still run on virtual threads.- Returns:
- virtual-thread
SimpleAsyncTaskExecutor(optionally bounded) namedfailover-scatter-*
-
failoverScanner
Registers a Spring-native scanner that locates all@Failover-annotated methods by walking the already-builtApplicationContext.- Returns:
SpringContextFailoverScanner
-
failoverStartupSummaryLogger
@ConditionalOnMissingBean @Bean public FailoverStartupSummaryLogger failoverStartupSummaryLogger(FailoverProperties properties, org.springframework.context.ApplicationContext applicationContext, org.springframework.beans.factory.ObjectProvider<FailoverScanner> scannerProvider) Logs a single consolidated startup summary covering infrastructure configuration and all discovered@Failoverendpoints. Fires onApplicationReadyEventso the scanner has already completed its scan before the summary is printed.- Parameters:
properties- failover configuration propertiesapplicationContext- Spring application context for bean-type detectionscannerProvider- optional failover scanner for per-endpoint details- Returns:
FailoverStartupSummaryLogger
-
recoveredPayloadHandler
Registers the default no-opRecoveredPayloadHandlerthat returns the payload unchanged.- Returns:
- pass-through
PassThroughRecoveredPayloadHandler
-
loggerObservablePublisher
Registers aObservablePublisherthat writes failover reports to SLF4J.- Returns:
MdcLoggerObservablePublisher
-
compositeObservablePublisher
@ConditionalOnMissingBean @Bean public CompositeObservablePublisher compositeObservablePublisher(List<ObservablePublisher> observablePublishers, FailoverClock clock) Registers a composite publisher that stamps the publish timestamp once and broadcasts to everyObservablePublisherin the context. Stamping once here ensures all delegates receive the same timestamp regardless of how many publishers are registered.- Parameters:
observablePublishers- allObservablePublisherbeans in the contextclock- clock used to stamp the single publish timestamp- Returns:
- composite publisher
-
failoverObservablePublisher
@ConditionalOnMissingBean(name="failoverObservablePublisher") @Bean(autowireCandidate=false) public ObservablePublisher failoverObservablePublisher(CompositeObservablePublisher composite, FailoverProperties properties) The dispatching publisher used by the failover handler and the startup observer — wrapping theCompositeObservablePublisherin anAsyncObservablePublisherso metric publishing can never block or slow the caller's@Failovercall (the core observability contract). Disable viafailover.observable.async.enabled=falseto publish synchronously (deterministic for tests).autowireCandidate = falseis essential: this bean is anObservablePublisherbut must never be collected intocompositeObservablePublisher(java.util.List<com.societegenerale.failover.core.observable.publisher.ObservablePublisher>, com.societegenerale.failover.core.clock.FailoverClock)'sList<ObservablePublisher>fan-out (that would recurse). Consumers therefore fetch it by name. The async instance'sclose()is invoked on shutdown by Spring's inferred destroy method, flushing the queue.- Parameters:
composite- the leaf fan-out publisher this decoratesproperties- async settings (enabled flag + queue capacity)- Returns:
- an
AsyncObservablePublisherwhen async is enabled (default), else the composite itself
-
failoverMetricsDroppedMeterBinder
@ConditionalOnClass(io.micrometer.core.instrument.MeterRegistry.class) @Bean public io.micrometer.core.instrument.binder.MeterBinder failoverMetricsDroppedMeterBinder(org.springframework.context.ApplicationContext applicationContext) Exposesfailover.metrics.dropped.totalwhen async publishing is active, so any metric dropped by a full queue is observable rather than silent. Bound only when the dispatching publisher is in fact anAsyncObservablePublisher(i.e. async enabled).- Parameters:
applicationContext- context used to resolve the (non-autowire-candidate) dispatching publisher by name- Returns:
- a
MeterBinderregistering the drop counter, or a no-op when publishing is synchronous
-
failoverCardinalityMeterFilter
@ConditionalOnClass(io.micrometer.core.instrument.config.MeterFilter.class) @ConditionalOnProperty(prefix="failover.observable.cardinality", name="enabled", havingValue="true", matchIfMissing=true) @Bean public io.micrometer.core.instrument.config.MeterFilter failoverCardinalityMeterFilter(FailoverProperties properties) Cardinality guard for thefailover.*meters: caps the number of distinctnametag values, denying further new series once the cap is hit so a misconfigured high-cardinality failover name can never explode the registry. On by default (failover.observable.cardinality).- Parameters:
properties- failover properties (cardinality cap)- Returns:
- a meter filter bounding the
nametag cardinality onfailover.*meters
-
failoverHandler
@ConditionalOnMissingBean @Bean public FailoverHandler<Object> failoverHandler(@Qualifier("failoverKeyGenerator") KeyGenerator keyGenerator, @Qualifier("failoverExpiryPolicy") ExpiryPolicy<Object> expiryPolicy, FailoverClock clock, FailoverStore<Object> failoverStore, PayloadEnricher<Object> payloadEnricher, RecoveredPayloadHandler recoveredPayloadHandler, org.springframework.context.ApplicationContext applicationContext, FailoverExpiryExtractor failoverExpiryExtractor, PayloadSplitterLookup<Object, Object> payloadSplitterLookup, @Qualifier("contextPropagator") ContextPropagator contextPropagator, @Qualifier("scatterGatherExecutor") org.springframework.beans.factory.ObjectProvider<org.springframework.core.task.TaskExecutor> scatterGatherExecutorProvider, FailoverProperties failoverProperties) Assembles the fullFailoverHandlerdecorator chain:AdvancedFailoverHandler(ScatterGatherFailoverHandler(DefaultFailoverHandler)).- Parameters:
keyGenerator- composite key generatorexpiryPolicy- composite expiry policyclock- failover clockfailoverStore- the assembled store (async/sync, single/multi-tenant)payloadEnricher- enriches payloads on storerecoveredPayloadHandler- handles recovered (or null) payloadsapplicationContext- resolves the (non-autowire-candidate) dispatching publisher by namefailoverExpiryExtractor- reads expiry from@FailoverpayloadSplitterLookup- looks up named splitter beanscontextPropagator- propagates thread context to scatter executor threadsscatterGatherExecutorProvider- optional executor for parallel scatter (null = sequential)failoverProperties- framework properties (provides the scatter slice timeout)- Returns:
- assembled
AdvancedFailoverHandler
-
methodExceptionHandler
@ConditionalOnMissingBean @Bean public MethodExceptionHandler methodExceptionHandler(MethodExceptionPolicy methodExceptionPolicy) Registers theMethodExceptionHandlerthat applies the active exception policy.- Parameters:
methodExceptionPolicy- active exception policy (rethrow, never-throw, or custom)- Returns:
MethodExceptionHandler
-
failoverExecution
@ConditionalOnProperty(prefix="failover", name="type", havingValue="basic", matchIfMissing=true) @ConditionalOnMissingBean @Bean public FailoverExecution<Object> failoverExecution(FailoverHandler<Object> failoverHandler, MethodExceptionHandler methodExceptionHandler, org.springframework.context.ApplicationContext applicationContext) RegistersBasicFailoverExecution, active whenfailover.type=basic(the default).- Parameters:
failoverHandler- assembled failover handlermethodExceptionHandler- exception handler applying the configured policyapplicationContext- resolves the non-blocking dispatching publisher (by name) for upstream-duration metrics- Returns:
BasicFailoverExecution
-
failoverAspect
@ConditionalOnProperty(prefix="failover", name="aspect.enabled", havingValue="true", matchIfMissing=true) @Bean public FailoverAspect<Object> failoverAspect(FailoverExecution<Object> failoverExecution) Registers the AOP aspect that intercepts@Failover-annotated methods.- Parameters:
failoverExecution- the configured failover execution strategy- Returns:
FailoverAspect
-
resourceLoader
Registers a resource loader for reading classpath resources (e.g.MANIFEST.MF).- Returns:
ClassPathResourceLoader
-
manifestInfoExtractor
@ConditionalOnMissingBean @Bean public ManifestInfoExtractor manifestInfoExtractor(ResourceLoader resourceLoader) Registers a caching manifest extractor for reading build metadata fromMANIFEST.MF.- Parameters:
resourceLoader- resource loader for reading MANIFEST.MF- Returns:
- caching wrapper around
DefaultManifestInfoExtractor
-
failoverObserver
@ConditionalOnMissingBean @Bean(initMethod="observe") public FailoverObserver failoverObserver(CompositeObservablePublisher observablePublisher, FailoverScanner failoverScanner, FailoverClock clock, ManifestInfoExtractor manifestInfoExtractor, FailoverExpiryExtractor failoverExpiryExtractor, FailoverProperties failoverProperties) Creates the failover reporter bean that publishes a startup summary.- Parameters:
observablePublisher- composite publisher that receives the startup reportfailoverScanner- scans for all@Failover-annotated methodsclock- clock for the report timestampmanifestInfoExtractor- extracts build info from MANIFEST.MFfailoverExpiryExtractor- reads expiry config from@FailoverfailoverProperties- active failover properties for inclusion in the report- Returns:
- reporter that publishes a full failover summary on application startup
-