Core Modules¶
Three modules form the non-negotiable foundation of every Failover installation: failover-domain, failover-core, and failover-aspect.
failover-domain¶
Provides the @Failover annotation and the two contracts for marking your domain types:
| Type | Kind | Purpose |
|---|---|---|
@Failover | Annotation | Declares failover behaviour on a method |
Referential | Abstract class | Extend to add upToDate, asOf, metadata fields |
ReferentialAware | Interface | Implement when inheritance is not possible |
Metadata | Class | Key/value carrier for optional context in Referential |
Add this to any module that annotates methods or defines referential domain types:
<dependency>
<groupId>com.societegenerale.failover</groupId>
<artifactId>failover-domain</artifactId>
<version>3.0.0</version>
</dependency>
failover-core¶
Provide an SLF4J logging implementation
failover-core depends on slf4j-api for logging but does not bundle any SLF4J implementation. Spring Boot users get Logback automatically via spring-boot-starter-logging. Without Spring Boot, add one explicitly:
Contains all SPI interfaces and their default implementations:
| Interface | Default implementation | Purpose |
|---|---|---|
FailoverHandler<T> | DefaultFailoverHandler | Store/recover/clean orchestration |
FailoverStore<T> | DefaultFailoverStore (delegates to impl) | Persistence contract |
KeyGenerator | DefaultKeyGenerator | Raw key from method args |
ExpiryPolicy<T> | DefaultExpiryPolicy | TTL computation and check |
PayloadEnricher<T> | DefaultPayloadEnricher | Enrich on store/recover |
PayloadSplitter<T,R> | (none — must provide your own) | Scatter/gather split/merge |
RecoveredPayloadHandler | (none — null by default) | Handle null recovery result |
ContextPropagator | CompositeContextPropagator(noOp) | Thread context across async slices |
FailoverScanner | SpringContextFailoverScanner (in failover-scanner) | Discovers @Failover methods and their payload types |
All beans use @ConditionalOnMissingBean in auto-configuration — declare your own @Bean to replace any default.
Scanner SPI package
FailoverScanner lives in com.societegenerale.failover.core.scanner (moved from core.observable.scanner in 3.0.0). It is a neutral shared component: observability reporting consumes the discovered annotations, and the JDBC store consumes findAllPayloadTypes() to build its deserialization allowlist. See ADR 42.
Handler Decorator Chain¶
flowchart TD
A[AdvancedFailoverHandler] --> S[ScatterGatherFailoverHandler]
S --> D[DefaultFailoverHandler] AdvancedFailoverHandler— adds metrics publishing andRecoveredPayloadHandlerinvocation.ScatterGatherFailoverHandler— intercepts whenpayloadSplitteris set; delegates directly toDefaultFailoverHandlerfor plain failovers. A thin facade over package-private collaborators —PayloadScatter(store side),PayloadGather(recover side),SliceDispatcher(parallel/sequential dispatch + per-slice timeout) andSplitterInvoker(splitter lookup and invocation). See ADR 49.DefaultFailoverHandler— core key/expiry/store/recover logic.
For the full store / recover / clean invocation order (and how it maps to the auto-configuration bean wiring), see How It Works — Handler Chain and Execution Order.
failover-aspect¶
Contains FailoverAspect, a Spring AOP @Around advice:
@Around("@annotation(failover)")
public Object failoverAround(ProceedingJoinPoint pjp, Failover failover) throws Throwable { /*...*/ }
The aspect:
- Resolves the annotated method's
@Failovermetadata and the reflectedMethod. - Hands off to
FailoverExecution.execute(failover, supplier, method, args), which proceeds (calls upstream). - On success:
FailoverExecutioncallsfailoverHandler.store(failover, method, args, result). - On exception:
FailoverExecutioncallsfailoverHandler.recover(failover, method, args, clazz, cause), thenMethodExceptionHandlerapplies the exception policy.
FailoverExecution is the thin wrapper that selects between BASIC (try/catch) and RESILIENCE (circuit-breaker) modes.
failover-store-inmemory¶
ConcurrentHashMap-backed store. Zero dependencies. Used as the default store when no other store module is on the classpath.
Not for production
InMemory store is not persistent. All cached data is lost on restart.
Next Steps¶
- JDBC Store — production-ready persistent store
- Async Store — non-blocking write decorator
- Reference — Interfaces — full SPI method signatures