Skip to content
Architecture Decisions

Decision Index

Architecture Decision Records

An architectural decision record (ADR) documents an important architectural choice along with its context and consequences.

Immutable history

ADRs are append-only. Once accepted, content is never changed. Superseded decisions are marked Deprecated with a cross-reference. New decisions always get the next sequential number.

Full decision text → adr.md


Decision Index

# Decision Date Status
ADR 1 — Build a failover lib Build a reusable annotation-driven failover library 10-NOV-2021 Accepted
ADR 2 — @Failover Annotations Dedicated @Failover annotation instead of reusing @FeignClient 10-NOV-2021 Accepted
ADR 3 — Metadata for referential : As Of , Up To Date ? Referential / ReferentialAware carry upToDate and asOf 15-NOV-2021 Accepted
ADR 4 — Recovered Payload Handler RecoveredPayloadHandler SPI for null/default handling 15-NOV-2021 Accepted
ADR 5 — Failover Store FailoverStore abstraction with InMemory, Caffeine, JDBC impls 16-NOV-2021 Accepted
ADR 6 — Failover Execution FailoverExecution SPI; BASIC (try/catch) and RESILIENCE variants 17-NOV-2021 Accepted
ADR 7 — Auto Cleanup Scheduled expiry cleanup via ExpiryCleanupScheduler 17-NOV-2021 Accepted
ADR 8 — Monitoring FailoverReporter with logger and Micrometer publishers 17-NOV-2021 Accepted
ADR 9 — Key Generator KeyGenerator SPI; default derives key from method args 30-DEC-2021 Accepted
ADR 10 — DefaultFailoverStore — Defensive Copy for Immutability Store clones ReferentialPayload to prevent caller mutation 25-MAY-2026 Accepted
ADR 11 — FailoverStoreBeanPostProcessor — Uniform Store Wrapping via BeanPostProcessor BeanPostProcessor wraps stores uniformly at startup 25-MAY-2026 Deprecated — superseded by ADR 16, ADR 18, ADR 19
ADR 12 — MethodExceptionPolicy — Pluggable Exception Handling Strategy ExceptionPolicy enum: RETHROW, NEVER_THROW, CUSTOM 26-MAY-2026 Accepted
ADR 13 — JDBC Native Merge/Upsert — Dialect Detection and Runtime Fallback Dialect-specific upsert with ANSI fallback 26-MAY-2026 Accepted
ADR 14 — DatabaseResolver — Strategy Interface for Database Product Detection DatabaseResolver SPI detects DB product at runtime 26-MAY-2026 Accepted
ADR 15 — FailoverStoreQueryResolver — Single-Responsibility Co-location of All JDBC Query Concerns All JDBC query building delegated to FailoverStoreQueryResolver 26-MAY-2026 Accepted
ADR 16 — Removal of BeanPostProcessor-based Store Wrapping (Supersedes ADR 11) BeanPostProcessor removed; auto-config assembles store chain explicitly 02-JUN-2026 Accepted — supersedes ADR 11
ADR 17 — TenantStoreFactory SPI — Abstracting Store Creation from Store Assembly TenantStoreFactory decouples per-tenant store creation 02-JUN-2026 Accepted
ADR 18 — FailoverStoreAutoConfiguration — Central Assembler Single auto-config class assembles the complete store chain 02-JUN-2026 Accepted
ADR 19 — FailoverStoreAsync — Explicit TaskExecutor Replacing @Async AsyncFailoverStore wraps delegate with explicit executor; drops @Async 02-JUN-2026 Accepted
ADR 20 — MultiTenantFailoverStore — Outermost Per-Tenant Routing Decorator Multi-tenant routing sits outside async decorator 02-JUN-2026 Accepted
ADR 21 — FailoverStoreMultiTenantAutoConfiguration — Multi-Tenant Auto-Configuration and TenantResolver SPI Separate auto-config for multi-tenant; TenantResolver SPI 02-JUN-2026 Accepted
ADR 22 — FailoverKeyGenerator — UUID-Based Key Normalisation for Fixed-Width Store Keys MD5/UUID key hash prevents VARCHAR(256) overflow 03-JUN-2026 Accepted
ADR 23 — PayloadSplitter — Scatter/Gather Storage for Composite-Key Failover PayloadSplitter<T,R> splits collection results into per-entity store entries 04-JUN-2026 Accepted
ADR 24 — Parallel Scatter/Gather — CompletableFuture with Injected Executor Scatter slices dispatched concurrently via injected Executor 04-JUN-2026 Accepted
ADR 25 — ContextPropagator SPI — Thread-Local Context Propagation for Parallel Scatter ContextPropagator captures and restores thread-local context on executor threads 04-JUN-2026 Accepted
ADR 26 — Replace LocalDateTime with Instant for Timezone-Aware Expiry Timestamps Instant eliminates timezone ambiguity in expiry across multi-node/multi-timezone deployments 06-JUN-2026 Accepted
ADR 27 — Migrate Deprecated JdbcTemplate Overloads in FailoverStoreJdbc Varargs overloads replace deprecated Object[] + int[] forms; removes java.sql.Types usage 06-JUN-2026 Accepted
ADR 28 — domain Attribute — Shared Store Partitioning Across @Failover Annotations domain enables scatter/gather slices and single-entity endpoints to share a store partition 07-JUN-2026 Accepted
ADR 29 — Observability Layer — Observer, Publisher SPI and MDC Logger Refactor Rename reporter stack to observer; MDC-safe publish via ObservablePublisher SPI; composite publisher 07-JUN-2026 Accepted
ADR 30 — SpringContextFailoverScanner — Replacing Reflections-Based Classpath Scanning Spring bean enumeration replaces Reflections; removes package-to-scan config and Guava dep 07-JUN-2026 Accepted
ADR 31 — failover-observable-micrometer — Micrometer Extension as an Optional Module Micrometer meters and Actuator health indicator extracted to an optional opt-in module 07-JUN-2026 Accepted
ADR 32 — PayloadSplitterExecutionException — Wrapping User-Splitter Failures with Diagnostic Context All PayloadSplitter call failures wrapped in PayloadSplitterExecutionException with splitter name and operation context 10-JUN-2026 Accepted
ADR 33 — doRecoverAll All-Slices Iteration — User-Controlled Slice Count doRecoverAll iterates over all slices returned by splitOnRecover; slice count is user-controlled via PayloadSplitter 10-JUN-2026 Accepted
ADR 34 — ScatterGatherFailoverHandler.recoverAll() Override — Clear Error for Scatter Case ScatterGatherFailoverHandler.recoverAll() overrides default with UnsupportedOperationException to prevent silent wrong-path execution 10-JUN-2026 Accepted
ADR 35 — Empty splitOnRecover Guard — Null Return Instead of merge([]) Guard against empty splitOnRecover result returns null rather than merging an empty list 10-JUN-2026 Accepted
ADR 36 — splitOnRecover RecoverAll Contract — Single Placeholder for DefaultFailoverHandler splitOnRecover must return exactly one placeholder context when delegating to DefaultFailoverHandler.recoverAll 10-JUN-2026 Accepted