Building Resilient .NET 8 Microservices with Polly 3.0 and Azure Service Bus

Mahmut Sarıkaya 4 dk okuma 10 Görüntülenme 0
Building Resilient .NET 8 Microservices with Polly 3.0 and Azure Service Bus

Why resilience matters for modern .NET 8 microservices

Imagine a payment gateway that suddenly loses its connection to a downstream inventory service. Without a fallback, the entire transaction chain stalls, leading to lost revenue and frustrated customers. In high‑frequency environments, even a 2% transient failure rate can translate into thousands of failed requests per hour. Building resilience into every service is no longer optional; it is a baseline requirement for reliable cloud‑native applications.

Understanding resilience patterns in .NET 8

.NET 8 introduces native support for async streams, minimal APIs, and improved AOT compilation, all of which reduce latency but do not eliminate external failures. The most common patterns—retry, timeout, bulkhead, and circuit breaker—address different failure modes. Retry smooths out brief network glitches, timeout prevents resource exhaustion, bulkhead isolates overload, and circuit breaker stops repeated calls to a failing dependency. Combining these patterns with Azure Service Bus, a highly available messaging backbone, creates a robust end‑to‑end flow.

Configuring Polly 3.0 circuit breaker for Service Bus consumers

Polly 3.0 adds source‑generated policies that reduce allocation overhead. A typical circuit‑breaker configuration for a Service Bus consumer might allow five consecutive exceptions before opening the circuit for 30 seconds. During the break, any incoming message is immediately moved to a dead‑letter queue, preserving order and avoiding endless retries.

using Polly;<br/>using Polly.CircuitBreaker;<br/>using Azure.Messaging.ServiceBus;<br/><br/>var circuitBreaker = Policy<ServiceBusReceivedMessage><br/>    .Handle<Exception>()<br/>    .CircuitBreakerAsync(<br/>        handledEventsAllowedBeforeBreaking: 5,<br/>        durationOfBreak: TimeSpan.FromSeconds(30));<br/><br/>var client = new ServiceBusClient(connectionString);<br/>var processor = client.CreateProcessor(queueName, new ServiceBusProcessorOptions());<br/><br/>processor.ProcessMessageAsync += async args =><br/>{<br/>    await circuitBreaker.ExecuteAsync(async () =><br/>    {<br/>        // Business logic here<br/>        Console.WriteLine(args.Message.Body);<br/>        await args.CompleteMessageAsync(args.Message);<br/>    });<br/>};<br/><br/>await processor.StartProcessingAsync();

Notice the use of Policy<ServiceBusReceivedMessage> which ensures the policy only executes when a message is successfully deserialized, keeping the error surface small.

Integrating Azure Service Bus retry policies with Polly

Azure Service Bus already retries transient network errors up to three times. To align with Polly, wrap the Service Bus client in a retry policy that mirrors the bus’s back‑off strategy: exponential growth with jitter. This prevents thundering‑herd effects when many instances reconnect simultaneously.

var retryPolicy = Policy<ServiceBusReceivedMessage>.Handle<ServiceBusException>(ex => ex.IsTransient)<br/>    .WaitAndRetryAsync(3, attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)) + TimeSpan.FromMilliseconds(new Random().Next(0, 100)));<br/><br/>await retryPolicy.ExecuteAsync(async () => { /* send or receive logic */ });

The jitter component (+0‑100 ms) is critical in production clusters with 10+ instances, as it spreads retry attempts over a wider time window.

Putting it all together in a minimal API microservice

A .NET 8 minimal API can expose an HTTP endpoint that forwards a payload to an Azure Service Bus topic. The endpoint applies a bulkhead limit of 20 concurrent calls, a timeout of 5 seconds, and the circuit‑breaker defined earlier. Below is a concise example that can be dropped into a new project.

var builder = WebApplication.CreateBuilder(args);<br/>builder.Services.AddSingleton(circuitBreaker);<br/>builder.Services.AddSingleton(retryPolicy);<br/>builder.Services.AddSingleton(new ServiceBusClient(connectionString));<br/>var app = builder.Build();<br/>app.MapPost("/orders", async (OrderDto order, ServiceBusClient sbClient, IAsyncPolicy<ServiceBusReceivedMessage> cb, IAsyncPolicy<ServiceBusReceivedMessage> rp) =>{<br/>    var sender = sbClient.CreateSender("orders-topic");<br/>    var message = new ServiceBusMessage(JsonSerializer.Serialize(order));<br/>    await rp.ExecuteAsync(() => sender.SendMessageAsync(message));<br/>    return Results.Accepted();<br/>}).AddEndpointFilter(async (context, next) =>{<br/>    using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));<br/>    var result = await cb.ExecuteAsync(() => next(context));<br/>    return result;<br/>});<br/>app.Run();

The endpoint filter applies the timeout and circuit‑breaker uniformly to all incoming HTTP calls, guaranteeing that a downstream Service Bus outage does not cascade into the API layer.

Monitoring and observability

Polly’s built‑in telemetry hooks can push metrics to Azure Monitor or Prometheus. Register an OnBreak and OnReset delegate to emit custom events. Pair these with Service Bus dead‑letter counts to get a full picture of failure patterns. For example, a spike in OnBreak events combined with a rising dead‑letter queue size indicates a downstream service degradation that warrants immediate investigation.

Conclusion

By leveraging Polly 3.0’s low‑overhead policies and Azure Service Bus’s durable messaging, .NET 8 microservices can achieve enterprise‑grade resilience without sacrificing performance. The key is to compose retry, timeout, bulkhead, and circuit‑breaker policies deliberately, monitor their state, and adjust thresholds based on real‑world traffic patterns. When each service respects these safeguards, the overall system remains responsive even under partial failures.

Sources

Microsoft Docs – Polly Integration Guide; Azure Documentation – Service Bus Best Practices; .NET Blog – Resilience Patterns in .NET 8

Author: Mahmut Sarıkaya — sarikayadev.com

Etiketler: #.NET 8 #Polly 3.0 #Azure Service Bus #microservice resilience #circuit breaker
Paylaş:
M

Yazar

Mahmut Sarıkaya

yazılım Geliştirici

Yorumlar

Henüz yorum yok. İlk yorumu siz yapın!

Yorum Bırakın

9 + 6 =