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 |