Introduction

Modern cloud applications operate in distributed environments where failures are inevitable. APIs become temporarily unavailable, databases experience connectivity issues, external services respond slowly, and network interruptions can occur at any time. While these failures may be short-lived, they can significantly impact application reliability if not handled properly.

Many developers assume that cloud services are always available, but in reality, even the most reliable systems occasionally experience transient faults. A resilient application is designed to detect, handle, and recover from these failures gracefully rather than crashing or returning errors to users.

This is where Polly becomes valuable. Polly is a popular .NET resilience library that helps developers implement fault-handling policies such as retries, circuit breakers, timeouts, fallback mechanisms, and rate limiting. When combined with ASP.NET Core, Polly enables teams to build applications that remain reliable even when dependent services fail.

In this article, you'll learn how Polly works, explore common resilience patterns, and discover best practices for building fault-tolerant cloud applications with ASP.NET Core.

Why Resilience Matters in Cloud Applications

Consider a typical cloud-based application:

Web API
    ↓
External API
    ↓
Database
    ↓
Message Queue

Every dependency introduces a potential point of failure.

Common issues include:

Without resilience mechanisms, a single dependency failure can impact the entire application.

Instead of treating failures as exceptional events, cloud-native applications should assume failures will happen and be prepared to recover automatically.

What Is Polly?

Polly is an open-source .NET library designed for transient fault handling and resilience.

It provides reusable policies that allow applications to react intelligently to failures.

Common Polly policies include:

These policies can be applied to:

Polly integrates seamlessly with ASP.NET Core and HttpClient, making it a popular choice for cloud-native applications.

Installing Polly

Install the required package:

dotnet add package Microsoft.Extensions.Http.Polly

This package enables Polly integration with HttpClientFactory.

Implementing Retry Policies

Transient failures are one of the most common cloud application issues.

Examples include:

A retry policy automatically attempts the operation again before returning an error.

Example:

builder.Services.AddHttpClient("WeatherApi")
    .AddTransientHttpErrorPolicy(policy =>
        policy.WaitAndRetryAsync(
            3,
            retryAttempt =>
                TimeSpan.FromSeconds(retryAttempt)));

In this example:

Retry policies improve reliability without requiring user intervention.

Using Exponential Backoff

Retrying immediately can sometimes worsen the problem.

A better approach is exponential backoff.

builder.Services.AddHttpClient("OrdersApi")
    .AddTransientHttpErrorPolicy(policy =>
        policy.WaitAndRetryAsync(
            3,
            retryAttempt =>
                TimeSpan.FromSeconds(
                    Math.Pow(2, retryAttempt))));

The delays become:

Retry 1 → 2 seconds
Retry 2 → 4 seconds
Retry 3 → 8 seconds

This reduces pressure on struggling services and improves recovery chances.

Implementing Circuit Breakers

Retries alone are not enough.

If a service remains unavailable, continuously retrying requests wastes resources.

Circuit breakers prevent repeated calls to failing services.

Example:

builder.Services.AddHttpClient("PaymentApi")
    .AddTransientHttpErrorPolicy(policy =>
        policy.CircuitBreakerAsync(
            5,
            TimeSpan.FromSeconds(30)));

In this configuration:

The workflow looks like this:

Service Healthy
      ↓
Requests Allowed
      ↓
Repeated Failures
      ↓
Circuit Opens
      ↓
Requests Blocked
      ↓
Recovery Check

Circuit breakers protect both your application and the failing service.

Adding Timeout Policies

Some failures occur because services respond too slowly.

Without timeouts, requests may remain active indefinitely.

Example:

builder.Services.AddHttpClient("InventoryApi")
    .AddPolicyHandler(
        Policy.TimeoutAsync<HttpResponseMessage>(
            TimeSpan.FromSeconds(5)));

If the request exceeds five seconds, Polly cancels the operation.

Benefits include:

Timeouts are especially important for high-traffic APIs.

Implementing Fallback Policies

Sometimes an application can continue operating even when a dependency fails.

Fallback policies provide alternative behavior.

Example:

var fallbackPolicy =
    Policy<string>
        .Handle<Exception>()
        .FallbackAsync(
            "Service temporarily unavailable");

Instead of returning an exception, the application provides a controlled response.

Common fallback scenarios include:

Fallbacks improve application availability during outages.

Combining Multiple Policies

The real power of Polly comes from combining policies.

Example:

builder.Services.AddHttpClient("ProductApi")
    .AddTransientHttpErrorPolicy(policy =>
        policy.WaitAndRetryAsync(3,
            retry => TimeSpan.FromSeconds(retry)))
    .AddTransientHttpErrorPolicy(policy =>
        policy.CircuitBreakerAsync(
            5,
            TimeSpan.FromSeconds(30)));

The workflow becomes:

Request
    ↓
Retry Policy
    ↓
Circuit Breaker
    ↓
External Service

This layered approach provides stronger resilience than any individual policy.

Using Polly with ASP.NET Core APIs

Suppose an API retrieves product data from an external service.

public class ProductService
{
    private readonly HttpClient _client;

    public ProductService(HttpClient client)
    {
        _client = client;
    }

    public async Task<string> GetProductsAsync()
    {
        return await _client.GetStringAsync(
            "/products");
    }
}

Because Polly policies are configured through HttpClientFactory, the service automatically benefits from:

No additional fault-handling code is required inside the service itself.

This keeps business logic clean and maintainable.

Common Resilience Patterns

PatternPurpose
RetryRecover from transient failures
Exponential BackoffReduce pressure during outages
Circuit BreakerPrevent repeated failures
TimeoutAvoid long-running requests
FallbackProvide alternative responses
Bulkhead IsolationLimit failure impact
Rate LimitingControl traffic volume

Most production applications use several of these patterns together.

Best Practices

Retry Only Transient Failures

Do not retry every error.

For example:

Retrying permanent failures wastes resources.

Use Exponential Backoff

Avoid aggressive retry behavior.

Exponential backoff reduces load on struggling services.

Implement Circuit Breakers for Critical Dependencies

External services should always be protected with circuit breakers.

This prevents cascading failures.

Configure Appropriate Timeouts

Timeout values should reflect business requirements.

Very short timeouts may cause unnecessary failures.

Very long timeouts may reduce responsiveness.

Monitor Resilience Metrics

Track:

These metrics help identify system weaknesses.

Combine Polly with Observability

Use OpenTelemetry, Application Insights, or other monitoring tools to visualize resilience events.

Observability helps teams understand how policies behave in production.

Common Mistakes to Avoid

MistakeImpact
Retrying every exceptionIncreased resource consumption
Missing circuit breakersCascading failures
Excessive retry attemptsService overload
No timeout policiesResource exhaustion
Ignoring monitoringLimited operational visibility
Hardcoded resilience settingsDifficult maintenance

Avoiding these mistakes improves application stability and maintainability.

Conclusion

Building resilient cloud applications requires more than simply handling exceptions. Modern distributed systems must be designed to anticipate failures and recover gracefully when they occur. Polly provides a powerful and flexible way to implement resilience patterns such as retries, circuit breakers, timeouts, and fallback mechanisms within ASP.NET Core applications.

By integrating Polly with HttpClientFactory and following proven resilience practices, development teams can reduce downtime, improve reliability, and create better user experiences even when dependent services encounter problems. As cloud architectures continue to evolve, resilience is becoming a core requirement rather than an optional enhancement, making Polly an essential tool for every ASP.NET Core developer building production-ready applications.