HCR082¶
Avoid per-request creation of resilience pipelines.
Why¶
ResiliencePipelineBuilder.Build() creates a reusable Polly pipeline. Building it inside a request path repeats configuration work and allocations for every request instead of reusing a singleton, typed-client, or cached pipeline configured at startup.
Bad¶
public sealed class PaymentsController
{
public void Post()
{
var pipeline = new ResiliencePipelineBuilder()
.AddRetry()
.Build();
pipeline.Execute();
}
}
Better¶
public sealed class PaymentsClient
{
private static readonly ResiliencePipeline Pipeline =
new ResiliencePipelineBuilder()
.AddRetry()
.Build();
public void Send()
{
Pipeline.Execute();
}
}
Prefer configuring outbound HTTP resilience through IHttpClientFactory and Microsoft.Extensions.Http.Resilience when the pipeline is specifically for HttpClient.
Current Detection¶
The implementation reports Polly.ResiliencePipelineBuilder.Build() calls inside obvious request paths. Request-path evidence includes controller/service-style type suffixes such as Controller, Endpoint, Handler, Worker, Service, Repository, and Job, plus Minimal API endpoint lambdas such as app.MapPost(..., () => ...).
It recognizes direct builder construction, fluent builder chains, and visible builder locals that have not been reassigned. Parentheses and null-forgiving operators are transparent around Polly builder and Minimal API endpoint-builder receivers. Static field initializers, startup/configuration types without request-path evidence, obvious test contexts, resolved custom builder lookalikes, and custom extension methods named Build are skipped.
Suppression¶
Suppress only when the request path intentionally builds a short-lived pipeline from request-specific configuration and the allocation/throughput cost is acceptable.