v1.0.0
Initial public release. Targets net10.0. Built for high-throughput microservices: hot paths are allocation-light, telemetry enrichment is cache-backed, and per-client resilience state is isolated by design.
Added
Pipelines
- Standard pipeline — timeout, retry, and circuit breaker strategies via
AddStandardResilienceHandler. Include"Standard"inPipelineOrderto enable. - Hedging pipeline — multiple concurrent requests with first-success-wins semantics for tail-latency-sensitive calls via
AddStandardHedgingHandler. Include"Hedging"inPipelineOrderto enable. Mutually exclusive with Standard. - Retry strategy — exponential, linear, and constant backoff modes with optional jitter and
Retry-Afterhonoring.BaseDelaySecondsisdoublefor sub-second delays. - Rate limiting — optional Polly rate limiter (
FixedWindow,SlidingWindow,TokenBucket). Registered as a per-client keyed singleton (key = HttpClient name), so each named HttpClient gets its own limiter and the container owns disposal. Resolve directly viaGetRequiredKeyedService<RateLimiter>(clientName)if needed. - Fallback — optional synthetic response on total failure, or custom fallback via
IHttpFallbackHandler(returnnullto fall through to synthetic response). Synthetic-only path is fully synchronous (no async state-machine allocation). - Bulkhead — optional Polly concurrency limiter to cap outbound concurrent requests.
Configuration
HttpResilienceOptionsroot configuration model with data-annotation validation, bound fromIConfigurationorIConfigurationSection.PipelineOrderlist controlling strategy ordering outermost→innermost (e.g.["Fallback", "Bulkhead", "Standard"]). Required whenEnabled = true; must contain exactly one ofStandardorHedging.PipelineSelection:Mode(None/ByAuthority) for per-authority pipeline instances.Enabledfeature flag — set tofalseto disable all resilience without code changes; validation short-circuits when disabled.ConnectionOptions.EnableMultipleHttp2Connections(defaulttrue) — maps toSocketsHttpHandler.EnableMultipleHttp2Connections. Allows multiple concurrent HTTP/2 TCP connections to a single origin so high-throughput clients are not bottlenecked on one connection's stream limit. Set tofalseto opt out.
Public API
AddHttpResilienceOptions— registersIOptions<HttpResilienceOptions>in DI with startup validation. Validator registered viaTryAddEnumerableso duplicate registrations across multiple HttpClients do not run validation N times.AddHttpClientWithResilience— wiresSocketsHttpHandlerplus resilience pipeline onto any named or typedHttpClient. Overloads acceptIConfiguration,IConfigurationSection, or DI-resolved options.AddHttpResilienceTelemetry— metrics enrichment witherror.type,request.name,request.dependency.nametags.AddHttpResilienceHealthChecks— aggregate circuit breaker health check for ASP.NET.configurePipelinedelegate — add extra strategies outermost.configureInnerPipelinedelegate — full code-level control over the inner pipeline (resolves options from DI).CircuitBreakerStateTracker.Enumerate()— public method returning a live, copy-free enumerator over tracked client states; backs the allocation-light health check path.
Internals
SocketsHttpHandlerFactory— configurable pool size, idle timeout, connection lifetime, connect timeout, and HTTP/2 multi-connection toggle.- Structured logging for retry, circuit breaker, and fallback events via
LoggerMessagesource generation. Retry log carriesint? StatusCodeas a discrete field (no per-retryHttpStatusCode.ToString()allocation). CircuitBreakerStateTracker— thread-safe state tracking backing the health check, with manual struct-enumerator iteration inHasOpenCircuits(no LINQ, no closure).PipelineStrategyNames.Allowed— backed byFrozenSet<string>for fastContainslookups during validation.
Tooling
- Sample console application in
samples/HttpResilience.NET.Sample(standalone package versions, independent of solution-wide central package management). - Unit and integration test suites.
- Documentation: IMPLEMENTATION, ARCHITECTURE, COMPARISON, OPERATIONS, RUNBOOK, RECIPES, TROUBLESHOOTING, VERSIONING, SECURITY-GOVERNANCE, PRODUCTION-CHECKLIST.
Performance
The following choices keep the per-request hot path allocation-light by design:
- Metering enricher (HttpResilienceMeteringEnricher):
- Canonical
HttpStatusCode.{n}strings precomputed into aFrozenDictionary<int, string>lookup table — no per-event interpolation. - Tag enumeration uses an index-based
forloop overIList<KeyValuePair<>>instead offoreach, avoiding the interface-enumerator allocation. - Single-pass scan over
context.Tagscollects bothpipeline.nameandstrategy.namein one traversal. pipeline/strategycomposite request name cached in aConcurrentDictionarykeyed by the small fixed pipeline/strategy name set; saturates fast then is allocation-free.scheme://host[:port]dependency name cached perUriinstance viaConditionalWeakTable<Uri, string>so repeated calls to the same host are allocation-free.tag.Value as stringfast path avoids virtualToString()when the underlying value is already a string.
- Canonical
- Health check —
HttpResilienceHealthChecklazily allocates the data dictionary and unhealthy list only when a non-closed breaker is observed; closed-state probes return without allocating.state.ToString()replaced by a small staticstring[]lookup keyed by(int)CircuitState. - Primary handler factory — uses
IOptionsMonitor<HttpResilienceOptions>(singleton) instead ofIOptionsSnapshot(scoped) insideConfigurePrimaryHttpMessageHandlerso handler builds do not allocate a fresh per-scope options copy. Hot-reload semantics preserved. - Fallback fast path —
ExecuteFallbackAsyncbuilds the synthetic response synchronously when no customIHttpFallbackHandleris configured; the async state machine is reserved for the slow path.