✨ Lightweight resilience toolkit for .NET
Retry policies · Circuit Breaker · Rate limiting (Token Bucket & Sliding Window) · Batch processing · ASP.NET Core Middleware · Metrics & Observability · Configurable Backoff Strategies
- Retry Policy – automatic retries with configurable backoff (Exponential, Linear, Fibonacci, Jitter)
- Circuit Breaker – prevent cascading failures and enable recovery
- Rate Limiting
- Token Bucket algorithm with async wait support
- Sliding Window algorithm for API-style quotas
- Batch Processing – collect and flush batches by size or interval
- ASP.NET Core Middleware – plug directly into your web pipeline with
UseResiliencePipeline() - Metrics & Observability Hooks –
IMetricsObserver/LoggingMetricsObserverfor complete visibility - Fluent Chaining – build pipelines with
.WithRetryAsync().WithCircuitBreakerAsync().WithSlidingWindowAsync().WithTokenBucketAsync() - Async-first – designed for modern .NET apps
- Lightweight – zero external dependencies
- 100% Test Coverage – verified via xUnit + Codecov
dotnet add package SteadyFlow.Resilienceusing SteadyFlow.Resilience.Retry;
using SteadyFlow.Resilience.Backoff;
var strategy = new JitterBackoffStrategy();
var retry = new RetryPolicy(maxRetries: 5, initialDelayMs: 200, strategy: strategy);
Func<Task<string>> unreliableAction = async () =>
{
if (new Random().Next(2) == 0)
throw new Exception("Transient failure");
return "Success!";
};
var pipeline = unreliableAction.WithRetryAsync(retry);
var result = await pipeline();
Console.WriteLine(result);using SteadyFlow.Resilience.Policies;
var breaker = new CircuitBreakerPolicy(failureThreshold: 2, openDuration: TimeSpan.FromSeconds(10));
Func<Task> riskyAction = async () =>
{
if (new Random().Next(3) == 0)
throw new Exception("Boom!");
await Task.CompletedTask;
};
var pipeline = riskyAction.WithCircuitBreakerAsync(breaker);
await pipeline();using SteadyFlow.Resilience.RateLimiting;
var limiter = new TokenBucketRateLimiter(capacity: 5, refillRatePerSecond: 2);
for (int i = 0; i < 10; i++)
{
await limiter.WaitForAvailabilityAsync();
Console.WriteLine($"Request {i} at {DateTime.Now:HH:mm:ss.fff}");
}var limiter = new SlidingWindowRateLimiter(maxRequests: 3, window: TimeSpan.FromSeconds(10));
for (int i = 0; i < 6; i++)
{
await limiter.WaitForAvailabilityAsync();
Console.WriteLine($"Request {i} at {DateTime.UtcNow:HH:mm:ss.fff}");
}using SteadyFlow.Resilience.Extensions;
using SteadyFlow.Resilience.Policies;
using SteadyFlow.Resilience.RateLimiting;
using SteadyFlow.Resilience.Retry;
var limiter = new TokenBucketRateLimiter(capacity: 2, refillRatePerSecond: 1);
var retry = new RetryPolicy(maxRetries: 3, initialDelayMs: 100);
var breaker = new CircuitBreakerPolicy(failureThreshold: 2, openDuration: TimeSpan.FromSeconds(10));
Func<Task> action = async () =>
{
if (new Random().Next(2) == 0)
throw new Exception("Simulated transient failure");
await Task.CompletedTask;
};
var pipeline = action
.WithTokenBucketAsync(limiter)
.WithRetryAsync(retry)
.WithCircuitBreakerAsync(breaker);
await pipeline();using Microsoft.Extensions.Logging;
using SteadyFlow.Resilience.Metrics;
ILoggerFactory factory = LoggerFactory.Create(b => b.AddConsole());
var observer = new LoggingMetricsObserver(factory.CreateLogger("resilience"));
observer.OnRetry(1, new Exception("Transient error"));
observer.OnCircuitOpened();
observer.OnRateLimited("TokenBucket");public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseResiliencePipeline(options =>
{
options.Retry = new RetryPolicy(maxRetries: 3);
options.CircuitBreaker = new CircuitBreakerPolicy(failureThreshold: 5, openDuration: TimeSpan.FromSeconds(30));
options.SlidingWindowLimiter = new SlidingWindowRateLimiter(maxRequests: 100, window: TimeSpan.FromMinutes(1));
});
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapControllers());
}- ✅ Unit tests for all policies, rate limiters, and middleware
- ✅ Integration and metrics tests with
IMetricsObserver - ✅ 100% code coverage via GitHub Actions + Codecov
Run locally:
dotnet test- Circuit Breaker policy
- Sliding Window rate limiter
- ASP.NET middleware integration
- Metrics & observability hooks
- Configurable backoff strategies (Jitter, Linear, Fibonacci)
- Advanced policy composition (PolicyRegistry / named pipelines)
- Built-in Prometheus metrics adapter
Contributions are welcome! Please see CONTRIBUTING.md for details.
- Fork the repo
- Create a feature branch
- Add tests & code
- Open a PR 🎉
If you find SteadyFlow.Resilience useful, please give it a ⭐ on GitHub — it helps others discover the project!
Licensed under the MIT License – see LICENSE for details.
