Loading repository data…
Loading repository data…
tiana-code / repository
A Spring Boot starter library of production-grade resilience and data quality patterns for distributed systems and microservices. Each pattern is self-contained, framework-agnostic at its core, and designed for high-throughput environments
A Spring Boot starter library implementing resilience and data quality patterns for distributed systems. Each pattern is self-contained and framework-agnostic at its core.
What it solves: Cascading failures when a downstream service degrades. Standard circuit breakers react only to hard errors; EWMA (Exponentially Weighted Moving Average) detects gradual degradation by tracking error rate over time.
When to use: Any external HTTP call, database, or third-party API that can go unavailable. Essential when downstream latency spikes cause upstream thread exhaustion.
How it works:
rate = alpha * outcome + (1 - alpha) * previousRateCallNotPermittedException (carries state, error rate, retry-after hint)AtomicReference<StateSnapshot> (no split-state race)failurePredicate - choose which exceptions count as failures (respected in both CLOSED and HALF_OPEN states)minimumCalls threshold - EWMA won't trip the breaker until enough observations collectedtransitionListener hook for metrics/logging on state changesClock for deterministic testing without Thread.sleepCheckedSupplier<T> / CheckedRunnable functional interfaces - supports checked exceptionsWhat it solves: Concurrency limits across multiple service instances - e.g., capping parallel calls to a paid API, limiting concurrent batch jobs, or protecting a weak downstream.
When to use: Multi-instance deployments where a local semaphore is not sufficient. Redis ZSET-backed leases with TTL prevent deadlocks on instance crash.
How it works:
leaseId as member and expiry epoch ms as scoreredis.call('TIME') - immune to JVM clock skewLease record carries leaseId, fencingToken, expiresAtMs, semaphoreName - used as handle for renew(Lease) / release(Lease) with ownership validationExponentialBackoff with jitterPEXPIRE (2x lease TTL) to prevent infinite key lifetimeZREMRANGEBYSCORE)acquireTimeout must not exceed leaseTtlWhat it solves: Unhealthy instances receiving traffic in a service mesh or client-side load balancer, even when the health endpoint briefly recovers.
When to use: Client-side load balancing or service registries where you need hysteresis - quarantine on sustained failure, release only on sustained recovery.
How it works:
HealthStatus records per instance with O(1) failure rate trackingCREATED -> STARTED -> CLOSEDstart() begins probing, close() shuts down with awaitTerminationIllegalStateExceptionHealthStatus records carry structured failureCause instead of sentinel valuesWhat it solves: Retry thundering herd - when all clients retry at the same intervals after a failure, they re-saturate the service simultaneously.
When to use: All retry loops for transient failures (network, DB, rate limits). Mandatory in distributed systems.
Implementations:
ExponentialBackoff - delay = min(initialDelay * multiplier^attempt, maxDelay) +/- jitterDecorrelatedJitter (AWS-style) - delay upper bound grows with attempt via base * 3^attempt, capped at cap. Use newSession() for per-chain state tracking with correlated previous delayBuilder validation: both strategies validate all invariants at build time (initialDelay > 0, maxDelay >= initialDelay, multiplier >= 1, jitterFactor in [0,1], base > 0, cap >= base)
Retry execution:
BackoffStrategy is a pure delay calculator: nextDelay(int attempt) -> DurationRetryExecutor handles the retry loop with configurable maxAttempts and retryOn(Predicate<Exception>) for exception classificationInterruptedException - restores interrupt flag and rethrowsWhat it solves: Corrupt, spoofed, or out-of-order GPS telemetry from vessel transponders and IoT sensors. Bad positions cause false route deviations, incorrect ETA calculations, and map rendering artifacts.
When to use: Any pipeline ingesting raw GPS data: vessel tracking, fleet management, logistics, IoT.
Validation stages:
speedKnots vs derived speed; rejects when ratio exceeds threshold (default: 3x)List<Consumer<GpsPoint>> notification chain (configured at construction)Note: filterAndValidate() compares each point against the previous accepted point, building a cleaned trajectory. This is an intentional policy choice.
Batch processing: filterAndValidate() returns BatchValidationResult with both accepted points and rejected entries (point + rejection reason) for debugging and quality monitoring.
GpsPoint validation: all fields validated at construction - latitude [-90, 90], longitude [-180, 180], hdop/speedKnots non-negative, courseDegreesTrue [0, 360), NaN/Infinity rejected.
Position prediction:
PositionPredictor uses bearing-based projection when courseDegreesTrue and speedKnots are available from the GPS sensorcos(bearing)/sin(bearing) with proper meters-per-degree scaling at current latitudehorizonSeconds validated to be positiveconfidenceScore is a heuristic decay function (half-life + trajectory variance), not a calibrated probabilitygraph TD
subgraph "system-design-patterns"
CB["EwmaCircuitBreaker\n(CLOSED / OPEN / HALF_OPEN)\nfailurePredicate + listener"]
DS["DistributedSemaphore\n(Redis ZSET + Lua + fencing)"]
HQ["HealthQuarantine\n(sliding window + virtual threads)\nCREATED / STARTED / CLOSED"]
BK["BackoffStrategy\nExponential / DecorrelatedJitter"]
RE["RetryExecutor\n(configurable retry loop)"]
GPS["GpsValidator\nSignalQuality - Order - Speed - Consistency"]
PP["PositionPredictor\n(bearing + speed projection)"]
end
App["Application code"] _-|"execute(checkedSupplier)"| CB
App _-|"tryAcquire() / release(lease)"| DS
App _-|"isQuarantined(instanceId)"| HQ
App _-|"nextDelay(attempt)"| BK
BK _-|"strategy"| RE
App _-|"validate(point, previous)"| GPS
App _-|"predict(history, horizon)"| PP
CB _-|"EWMA error rate"| CB
DS _-|"Redis ZSET + TIME"| Redis[(Redis)]
HQ _-|"HTTP GET /health"| Instances["Service instances"]
EwmaCircuitBreaker + RetryExecutorDistributedSemaphore to cap parallel calls to shared resources (payment processor, SMS gateway)GpsValidator.filterAndValidate(), inspect BatchValidationResult.rejected() for quality monitoringHealthQuarantine, call start(), filter getHealthyInstances() before routing, close() on shutdownDistributedSemaphore only)system-design:
circuit-breaker:
alpha: 0.2 # EWMA smoothing factor (0, 1]
failure-rate-threshold: 0.5 # Open circuit above 50% error rate (0, 1]
recovery-timeout: 30s
half-open-permitted-calls: 3
minimum-calls: 10 # EWMA won't trip until this many calls observed
semaphore:
name: default
default-permits: 10
default-lease-ttl: 30s
default-acquire-timeout: 10s # Must not exceed default-lease-ttl
health-quarantine:
window-size: 10
failure-threshold: 0.6 # Quarantine above 60% failure rate (0, 1]
recovery-checks: 3
check-interval: 15s
request-timeout: 5s
backoff:
initial-delay: 100ms
max-delay: 30s # Must be >= initial-delay
multiplier: 2.0 # >= 1
jitter-factor: 0.1 # [0, 1]
gps:
max-speed-knots: 50.0
max-hdop: 10.0
predictor-history-points: 10
All properties are validated at startup via Jakarta Bean Validation (@Validated, @Positive, @DecimalMin, @DecimalMax, @NotNull, @AssertTrue for cross-field invariants). Invalid configuration produces a clear binding error instead of a silent runtime failure.
Auto-configuration is split into modular nested @Configuration classes with @ConditionalOnClass guards, so only relevant beans are created based on classpath availability.
0.1.0 - API is stabilising but not yet frozen. Minor versions may include breaking changes until 1.0.0.
MIT - see LICENSE