Skip to content

societe-generale/failover

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

175 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

CI Coverage Maven Central Java 21+ Spring Boot 4.x Apache 2.0


Failover logo

Failover

Stop cascading outages. One annotation.

Transparent failover for referential services — annotation-driven, Spring Boot native.


The problem

In microservice platforms your application calls services it doesn't own — currency tables, country lists, client profiles. When those fail the cascade reaches your users, and there is nothing you can do to fix the upstream.

Service dependency model: internal, transversal, and external services

One outage in a transversal or external service cascades through every dependent service, returning 500s to users who have no visibility into why.

Cascade failure: external service failure propagates to end users as 500 errors


The solution

Failover sits between your service and the referential system. On success it stores the result with a configured TTL. On failure it serves the last known-good value — transparently, with zero boilerplate.

Failover library inserted between service and referential system with a local FailoverStore

Failover stores responses on success and replays last-known-good on failure with per-referential expiry

// Before: bespoke, brittle, repeated everywhere
public Country findByCode(String code) {
    try {
        Country c = upstream.findByCode(code);
        localRepo.save(c, computeExpiry());
        return c;
    } catch (Exception e) {
        Country cached = localRepo.findByCode(code);
        if (cached == null || isExpired(cached)) throw e;
        cached.setUpToDate(false);
        return cached;
    }
}

// After: declarative, consistent, zero boilerplate
@Failover(name = "country-by-code", expiryDuration = 24, expiryUnit = ChronoUnit.HOURS)
Country findByCode(String code);

User impact

Without Failover a referential failure returns a 500 and blocks the user completely. With Failover the last stored result is served — marked with its cached timestamp, but fully functional.

Three states: all services available, external service down without failover (error page), external service down with failover (stale data served)


Quick start

Add the starter:

<dependency>
    <groupId>com.societegenerale.failover</groupId>
    <artifactId>failover-spring-boot-starter</artifactId>
    <version><!-- latest --></version>
</dependency>

Configure a store:

failover:
  store:
    type: jdbc                    # inmemory | caffeine | jdbc

Annotate your interface:

@Failover(name = "country-by-code", expiryDuration = 24, expiryUnit = ChronoUnit.HOURS)
Country findByCode(String code);

Full walkthrough → Quickstart guide


Key features

Feature Description
Automatic store on success Every successful response persisted under a derived key — no explicit save calls
Transparent recovery on failure Last stored result returned when upstream throws — callers never see the exception
Business-configured TTL Fixed duration, SpEL expression, or a custom ExpiryPolicy
Pluggable backing stores InMemory · Caffeine · JDBC (H2 / PostgreSQL / MySQL / Oracle) · custom FailoverStore
Scatter / Gather Collection-returning methods split into per-entity entries; partial recovery handled automatically
Multi-tenant isolation TABLE_PREFIX or SCHEMA strategy routes each request to the correct tenant store
Async non-blocking writes Store operations offloaded to a virtual-thread executor; read path stays synchronous
Observable out of the box Every store/recover event emits SLF4J logs and Micrometer counters — no extra instrumentation
Resilience4j integration Circuit-breaker wraps upstream calls when type: resilience

Module structure

failover-spring-boot-starter          ← the only dependency you need
├── failover-domain                   @Failover · Referential · ReferentialAware · Metadata
├── failover-core                     FailoverHandler · KeyGenerator · ExpiryPolicy · PayloadEnricher
├── failover-aspect                   Spring AOP @Around interceptor
├── failover-store-inmemory           ConcurrentHashMap store — dev/test only
├── failover-store-caffeine           Caffeine-backed in-process store
├── failover-store-jdbc               JDBC store — H2 · PostgreSQL · MySQL · MariaDB · Oracle
├── failover-store-async              Non-blocking write decorator (virtual-thread executor)
├── failover-store-multitenant        TABLE_PREFIX / SCHEMA per-tenant routing
├── failover-execution-resilience     Resilience4j circuit-breaker integration
├── failover-scheduler                Expiry-cleanup · report-publisher schedulers
└── failover-spring-boot-autoconfigure  Zero-config Spring Boot auto-configuration

Monitoring

Failover emits Micrometer counters for every store and recover event. Connect to Elastic, Grafana, or any compatible backend.

Kibana dashboard showing all active failover configurations: name, expiry duration, expiry unit, type

The configuration dashboard shows all active @Failover configurations at a glance — discovered automatically from the Spring context.

Chart Description
Failover rate Failover rate — total upstream failures intercepted per referential
Recovery rate Recovery rate — failures resolved with a stored result (users unblocked)
Non-recovery rate Non-recovery rate — failures with no stored result (actual user impact)

Documentation

Page Description
Quickstart Working end-to-end example in 5 minutes
Installation Maven and Gradle coordinates for every module
Concepts Store/recover lifecycle, key derivation, expiry policies
Configuration reference Every failover.* property with types and defaults
ADR index 25 architecture decisions — the why behind every design choice

Contributing

Bug reports, feature proposals, and pull requests are welcome. See CONTRIBUTING for guidelines.

Acknowledgements

Built at Société Générale to break referential-outage cascades once, reusably, across every service.

  • Anand Manissery — creator and maintainer
  • Vincent Fuchs — contributions and review
  • Patrice Fricard, Igor Lovich, Abilash Titus — early contributors

Licensed under Apache 2.0.

About

A generic lib to manage the failover on external referential service

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors