HTTP Resilience — Retry, Circuit Breaker & Timeout
Overview
Section titled “Overview”Granit.Http.Resilience wraps Microsoft.Extensions.Http.Resilience
(built on Polly v8) and exposes a single AddGranitHttpClient() extension that replaces
bare AddHttpClient() calls across all Granit modules. Every outbound HTTP call
automatically benefits from retry with exponential back-off, circuit breaking, and
per-request timeouts.
Default pipeline
Section titled “Default pipeline”| Stage | Default |
|---|---|
| Total timeout | 30 s |
| Retry | 3 attempts, exponential back-off (2 s base) |
| Circuit breaker | Opens after 10 failures in 30 s, stays open for 1 min |
| Per-attempt timeout | 10 s |
These defaults come from AddStandardResilienceHandler() and apply to every client
registered via AddGranitHttpClient().
Registration
Section titled “Registration”// Drop-in replacement for AddHttpClient()services.AddGranitHttpClient("granit-webhooks", (sp, client) =>{ client.BaseAddress = new Uri("https://webhook-receiver.example.com/"); client.Timeout = TimeSpan.FromSeconds(10);});The returned IHttpClientBuilder can be chained for further customization.
Auth token propagation
Section titled “Auth token propagation”In microservice architectures, downstream services often need the same JWT token that
the incoming request carries. AddAuthTokenPropagation() adds a DelegatingHandler
that reads the Authorization header from the current HttpContext and sets it on
every outgoing request automatically.
services.AddGranitHttpClient("catalog-service") .AddAuthTokenPropagation();Combine with Aspire service discovery for zero-configuration inter-service calls:
services.AddGranitHttpClient("catalog-service", client => client.BaseAddress = new Uri("https+http://catalog-service")) .AddAuthTokenPropagation();Per-client configuration
Section titled “Per-client configuration”Override pipeline settings per named client in appsettings.json without redeploying:
{ "HttpResilience": { "granit-webhooks": { "Retry": { "MaxRetryAttempts": 5 }, "CircuitBreaker": { "SamplingDuration": "00:01:00", "MinimumThroughput": 20 } }, "KeycloakAdmin": { "Retry": { "MaxRetryAttempts": 1 } } }}Settings from HttpResilience:{clientName} are applied on top of the defaults at
runtime via IPostConfigureOptions<HttpStandardResilienceOptions>.
Affected modules
Section titled “Affected modules”All Granit modules that register outbound HttpClient instances declare
[DependsOn(typeof(GranitHttpResilienceModule))] and call AddGranitHttpClient():
| Module | Client name | Notes |
|---|---|---|
Granit.Webhooks | granit-webhook-delivery | Webhook delivery |
Granit.Notifications.Twilio | Twilio | SMS + WhatsApp |
Granit.Notifications.Brevo | Brevo | Email + SMS + WhatsApp |
Granit.Notifications.Zulip | Zulip | Chat |
Granit.Notifications.Email.SendGrid | SendGrid | |
Granit.Notifications.Email.Scaleway | Scaleway | |
Granit.Notifications.MobilePush.GoogleFcm | GoogleFcmPush | Mobile push |
Granit.Identity.Keycloak | KeycloakAdmin | Admin API |
Granit.Identity.EntraId | MicrosoftGraph | Graph API |
Granit.AI.Ollama | GranitAIOllamaHealthCheck | Health check |
Architecture
Section titled “Architecture”graph TD
GHR[Granit.Http.Resilience] --> MEHR[Microsoft.Extensions.Http.Resilience]
MEHR --> POLLY[Polly v8]
GHR --> WEBHOOKS[Granit.Webhooks]
GHR --> NOTIF[Granit.Notifications.*]
GHR --> IDENTITY[Granit.Identity.*]
GHR --> AI[Granit.AI.Ollama]
Compliance
Section titled “Compliance”- ISO 27001 A.17.1 — service continuity: circuit breaking prevents cascade failures when a downstream dependency is unavailable
- GDPR Article 32 — availability: resilience policies reduce data-processing downtime caused by transient network or API errors
Further reading
Section titled “Further reading”- Webhooks — uses
granit-webhook-deliveryclient - Notifications — notification provider clients
- Microsoft.Extensions.Http.Resilience docs