Readable by design
Shield.When<TimeoutException>().Retry(3) reads like intent, not infrastructure. Use concise defaults or take full control with options objects.
Fast resilience for .NET. Every strategy you need, composed through one fluent shield API.
dotnet add package Kevlarvar shield = Shield
.Timeout(TimeSpan.FromSeconds(30))
.Retry(3)
.CircuitBreaker(
5,
breakDuration: TimeSpan.FromSeconds(30));
var user = await shield.ExecuteAsync(
ct => LoadUserAsync(id, ct), cancellationToken);
Kevlar strips away accidental complexity without giving up the control, performance or observability production systems need.
Shield.When<TimeoutException>().Retry(3) reads like intent, not infrastructure. Use concise defaults or take full control with options objects.
Struct outcomes, pooled contexts, state-passing overloads and ValueTask end to end keep successful calls fast and allocation-free.
Shield.Retry(3) includes exponential backoff with jitter, capped at 30 seconds—the production setting you wanted anyway.
Chain strategies fluently. Merge shields with Wrap and Compose. Reuse one instance when state should be shared.
Core Kevlar depends on nothing but the BCL. No surprise transitive packages, version conflicts or dependency-tree baggage.
Targets netstandard2.0 and net8.0, with integrations for Microsoft DI and HttpClientFactory.
Successful Retry(3) execution
Allocated on the happy path
In the core package
Build complete resilience pipelines from focused strategies. Sensible defaults keep common cases concise; options objects give you full control when you need it.
var shield = Shield
.Timeout(TimeSpan.FromSeconds(30))
.Retry(3)
.CircuitBreaker(5,
breakDuration: TimeSpan.FromSeconds(30));
var search = Shield.For<HttpResponseMessage>()
.When<HttpRequestException>()
.OrResult(r => (int)r.StatusCode is >= 500 or 429)
.Fallback((outcome, ct) => cache.GetCachedAsync(ct))
.Retry(o =>
{
o.MaxRetries = 4;
o.DelayGenerator = e =>
e.Outcome.Result?.Headers.RetryAfter?.Delta;
o.OnRetry = e => logger.LogWarning(
"retry {Attempt} in {Delay}", e.Attempt, e.Delay);
})
.CircuitBreaker(o =>
{
o.FailureRatio = 0.5;
o.SamplingWindow = TimeSpan.FromSeconds(30);
o.Monitor = monitor;
})
.Hedge(maxAttempts: 2, delay: TimeSpan.FromMilliseconds(150))
.Timeout(TimeSpan.FromSeconds(2))
.WithName("search");