Resilience and concurrency toolkit for Elixir.
This library bundles six complementary modules that help your application handle failures, bound concurrency, and reduce tail latency — all with zero runtime dependencies.
Modules
Resiliency.CircuitBreaker— Circuit breaker with sliding window failure-rate tracking and automatic recovery.Resiliency.BackoffRetry— Functional retry with composable, stream-based backoff strategies.Resiliency.Hedged— Hedged requests: fire a backup after a delay, take whichever finishes first.Resiliency.SingleFlight— Deduplicate concurrent function calls by key.Resiliency.Race— Run functions concurrently, return the first success, cancel the rest.Resiliency.AllSettled— Run functions concurrently, collect every result regardless of failures.Resiliency.Map— Map over an enumerable with bounded concurrency, cancel on first error.Resiliency.FirstOk— Try functions sequentially, return the first success.Resiliency.WeightedSemaphore— Weighted semaphore for bounding concurrent access to a shared resource.
Common API patterns
Most modules in this library follow a consistent workflow:
Start — Add the module to your supervision tree (where applicable).
Resiliency.CircuitBreaker,Resiliency.Hedged(adaptive mode),Resiliency.SingleFlight, andResiliency.WeightedSemaphorerequire a running process.BackoffRetry,Race,AllSettled,Map,FirstOk, and statelessHedged.run/2are purely functional.Call — Wrap your operation in a zero-arity function and pass it to the module's primary entry point:
# Retry Resiliency.BackoffRetry.retry(fn -> fetch(url) end, max_attempts: 5) # Hedged (stateless) Resiliency.Hedged.run(fn -> fetch(url) end, delay: 100) # Hedged (adaptive) Resiliency.Hedged.run(MyHedge, fn -> fetch(url) end) # SingleFlight Resiliency.SingleFlight.flight(MyFlights, "user:123", fn -> load_user(123) end) # Race Resiliency.Race.run([fn -> svc_a() end, fn -> svc_b() end]) # WeightedSemaphore Resiliency.WeightedSemaphore.acquire(MySem, 3, fn -> bulk_insert(rows) end) # CircuitBreaker Resiliency.CircuitBreaker.call(MyBreaker, fn -> HttpClient.get(url) end)Handle the result — Every module returns
{:ok, value}on success and{:error, reason}on failure, so pattern matching is uniform across the entire toolkit.
Combine modules for layered resilience — for example, wrap a hedged call inside a retry, or protect a retried call behind a weighted semaphore to avoid overwhelming a downstream service.