ZeroAlloc.Resilience 1.3.0

dotnet add package ZeroAlloc.Resilience --version 1.3.0
                    
NuGet\Install-Package ZeroAlloc.Resilience -Version 1.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ZeroAlloc.Resilience" Version="1.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ZeroAlloc.Resilience" Version="1.3.0" />
                    
Directory.Packages.props
<PackageReference Include="ZeroAlloc.Resilience" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ZeroAlloc.Resilience --version 1.3.0
                    
#r "nuget: ZeroAlloc.Resilience, 1.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ZeroAlloc.Resilience@1.3.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ZeroAlloc.Resilience&version=1.3.0
                    
Install as a Cake Addin
#tool nuget:?package=ZeroAlloc.Resilience&version=1.3.0
                    
Install as a Cake Tool

ZeroAlloc.Resilience

NuGet Build License: MIT AOT GitHub Sponsors

Source-generated, zero-allocation resilience policies for .NET.

Add [Retry], [Timeout], [RateLimit], and [CircuitBreaker] to an interface. A Roslyn source generator emits a proxy class that composes all policies in declaration order with no heap allocation on the happy path (beyond the unavoidable CancellationTokenSource for timeout). AOT-safe.


Quick start

dotnet add package ZeroAlloc.Resilience
[Retry(MaxAttempts = 3, BackoffMs = 200, Jitter = true, PerAttemptTimeoutMs = 1_000)]
[Timeout(Ms = 5_000)]
[RateLimit(MaxPerSecond = 100, BurstSize = 10)]
[CircuitBreaker(MaxFailures = 5, ResetMs = 1_000, HalfOpenProbes = 1, Fallback = nameof(FetchFallback))]
public interface IExternalService
{
    ValueTask<string> FetchAsync(string id, CancellationToken ct);
    ValueTask<string> FetchFallback(string id, CancellationToken ct);
}

// Register — one line wires everything
builder.Services.AddExternalServiceResilience<ExternalServiceImpl>();

Inject IExternalService anywhere — all policies are transparent to the caller.


Performance

Head-to-head vs Polly v8 (the de-facto resilience library in .NET). .NET 10.0.7, BenchmarkDotNet v0.14.0.

Operation Polly v8 ZA.Resilience Speedup
Retry, happy path 600 ns / 64 B 23 ns / 0 B 26× faster, 0 B alloc
CircuitBreaker, closed 776 ns / 64 B 17 ns / 0 B 45× faster, 0 B alloc
Retry with 2/3 failures 22.9 ms / 3,134 B 27.9 ms / 948 B 22% slower wall-clock, 3.3× less alloc

The happy-path gap is driven by Polly's ResiliencePipeline.ExecuteAsync walking the strategy chain via delegate dispatch and allocating a ResilienceContext per call (64 B). ZA emits one direct method per interface — retry/CB checks are inline if statements with no context object or closure.

The retry-with-failures wall-clock gap is dominated by Task.Delay(BackoffMs); the residual 22% is ZA's for-loop scheduling — measurable, but mostly invisible against I/O latency.

Full methodology + self-benchmark: docs/performance.md.

Features

Feature Notes
Zero allocation on happy path Policy checks are integer comparisons and CAS operations
AOT / trimmer safe Generated proxy is concrete; no reflection at runtime
Retry with exponential backoff Jitter, per-attempt timeout, total timeout all configurable
Timeout Total operation timeout wrapping all retries and backoff delays
Rate limiting Lock-free token bucket; Shared (singleton) or Instance (per-proxy) scope
Circuit breaker Closed → Open → HalfOpen FSM backed by ZeroAlloc.StateMachine (concurrent CAS)
Fallback Method called when circuit is open — same signature, no allocation
Result<T> support Return Result<T> to get failures without exceptions
Method-level overrides Any attribute on a method shadows the interface-level config for that method
DI integration Generated Add{Service}Resilience<TImpl>() extension registers everything

Policy execution order

Policies execute in this order on every call:

RateLimit → CircuitBreaker → Timeout → Retry (with PerAttemptTimeout inside)

Each policy runs before the inner call is even attempted. If the rate limiter rejects, the circuit breaker and retry logic are never reached.


Attribute overview

[Retry]

[Retry(MaxAttempts = 3, BackoffMs = 200, Jitter = true, PerAttemptTimeoutMs = 1_000)]
Property Type Default Description
MaxAttempts int 3 Total attempts (initial + retries)
BackoffMs int 200 Base backoff ms; actual = BackoffMs * 2^attempt
Jitter bool false Add up to 50% random jitter to prevent thundering-herd
PerAttemptTimeoutMs int 0 Per-attempt cancellation timeout; 0 = disabled

[Timeout]

[Timeout(Ms = 5_000)]
Property Type Default Description
Ms int required Total operation timeout wrapping all retries and backoff

[RateLimit]

[RateLimit(MaxPerSecond = 100, BurstSize = 10, Scope = RateLimitScope.Shared)]
Property Type Default Description
MaxPerSecond int required Token refill rate
BurstSize int 1 Initial and peak token count
Scope RateLimitScope Shared Shared = singleton per interface; Instance = per proxy

[CircuitBreaker]

[CircuitBreaker(MaxFailures = 5, ResetMs = 1_000, HalfOpenProbes = 1, Fallback = nameof(FetchFallback))]
Property Type Default Description
MaxFailures int 5 Consecutive failures that trip Closed → Open
ResetMs int 1_000 Delay before Open → HalfOpen
HalfOpenProbes int 1 Successes required to close from HalfOpen
Fallback string? null Fallback method name — called when circuit is Open

Method-level overrides

Apply attributes directly to methods to override the interface-level config for that method only:

[Retry(MaxAttempts = 3, BackoffMs = 200)]
public interface IExternalService
{
    ValueTask<string> FetchAsync(string id, CancellationToken ct); // uses interface-level

    [Retry(MaxAttempts = 1)]   // POST is not idempotent — one attempt only
    ValueTask PostAsync(string data, CancellationToken ct);
}

Method-level attributes shadow interface-level ones entirely for that method — they are not additive.


Failure surface

Return type On failure
ValueTask<T> / Task<T> ResilienceException thrown with Policy property
ValueTask<Result<T>> / Task<Result<T>> Result.Failure(...) returned — no throw
try
{
    var result = await service.FetchAsync("id", ct);
}
catch (ResilienceException ex) when (ex.Policy == ResiliencePolicy.CircuitBreaker)
{
    // circuit was open and no fallback was configured
}

Diagnostics

ID Severity Description
ZR0001 Error Fallback method not found or signature mismatch
ZR0002 Warning Timeout configured but method has no CancellationToken

Documentation

Full docs live in docs/:


License

MIT

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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 is compatible.  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 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (8)

Showing the top 5 NuGet packages that depend on ZeroAlloc.Resilience:

Package Downloads
ZeroAlloc.Scheduling

Source-generated zero-allocation background job scheduling for .NET.

ZeroAlloc.Outbox

Source-generated transactional outbox for .NET.

AI.Sentinel

Security monitoring middleware for IChatClient — prompt injection, hallucination, and operational anomaly detection with an intervention engine.

ZeroAlloc.Rest.Resilience

Wires ZeroAlloc.Rest clients through ZeroAlloc.Resilience proxies. Annotate a [ZeroAllocRestClient] interface with [Retry]/[Timeout]/[CircuitBreaker]; call AddRestResilience to register the resilience-wrapped HTTP client.

ZeroAlloc.Scheduling.Resilience

ZeroAlloc.Resilience bridge for ZeroAlloc.Scheduling — wraps IJobTypeExecutor implementations in a Resilience-generated proxy.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.0 1,886 5/13/2026
1.2.2 232 5/12/2026
1.2.1 326 5/3/2026
1.2.0 154 5/1/2026
1.1.3 96 5/1/2026
1.1.2 96 4/29/2026
1.1.1 98 4/28/2026
1.1.0 109 4/25/2026
1.0.3 2,823 4/23/2026
1.0.2 120 4/22/2026
1.0.0 6,910 4/19/2026