SteadyFlow.Resilience
0.2.0
dotnet add package SteadyFlow.Resilience --version 0.2.0
NuGet\Install-Package SteadyFlow.Resilience -Version 0.2.0
<PackageReference Include="SteadyFlow.Resilience" Version="0.2.0" />
<PackageVersion Include="SteadyFlow.Resilience" Version="0.2.0" />
<PackageReference Include="SteadyFlow.Resilience" />
paket add SteadyFlow.Resilience --version 0.2.0
#r "nuget: SteadyFlow.Resilience, 0.2.0"
#:package SteadyFlow.Resilience@0.2.0
#addin nuget:?package=SteadyFlow.Resilience&version=0.2.0
#tool nuget:?package=SteadyFlow.Resilience&version=0.2.0
<p align="center"> <img src="assets/steadyflow_logo_banner.png" alt="SteadyFlow Logo" width="700"/> </p>
SteadyFlow.Resilience
✨ 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
✨ Features
- 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
📦 Installation
dotnet add package SteadyFlow.Resilience
🚀 Usage Examples
🔁 Retry with Custom Backoff
using 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);
⚡ Circuit Breaker
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();
📊 Rate Limiting
Token Bucket
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}");
}
Sliding Window
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}");
}
🔗 Fluent Integration Example
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();
📈 Metrics & Observability
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");
🌐 ASP.NET Core Middleware
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());
}
🧪 Tests
- ✅ 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
📈 Roadmap
- 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
🤝 Contributing
Contributions are welcome! Please see CONTRIBUTING.md for details.
- Fork the repo
- Create a feature branch
- Add tests & code
- Open a PR 🎉
⭐ Support
If you find SteadyFlow.Resilience useful, please give it a ⭐ on GitHub — it helps others discover the project!
📄 License
Licensed under the MIT License – see LICENSE for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.AspNetCore.Http (>= 2.3.0)
- Microsoft.Extensions.Logging (>= 8.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.