RepoPilotOpen in app →

App-vNext/Polly

Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner. From version 6.0.1, Polly targets .NET Standard 1.1 and 2.0+.

Healthy

Healthy across the board

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 1d ago
  • 6 active contributors
  • BSD-3-Clause licensed
Show 3 more →
  • CI configured
  • Tests present
  • Concentrated ownership — top contributor handles 70% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/app-vnext/polly)](https://repopilot.app/r/app-vnext/polly)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/app-vnext/polly on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: App-vNext/Polly

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/App-vNext/Polly shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 1d ago
  • 6 active contributors
  • BSD-3-Clause licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership — top contributor handles 70% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live App-vNext/Polly repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/App-vNext/Polly.

What it runs against: a local clone of App-vNext/Polly — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in App-vNext/Polly | Confirms the artifact applies here, not a fork | | 2 | License is still BSD-3-Clause | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>App-vNext/Polly</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of App-vNext/Polly. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/App-vNext/Polly.git
#   cd Polly
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of App-vNext/Polly and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "App-vNext/Polly(\\.git)?\\b" \\
  && ok "origin remote is App-vNext/Polly" \\
  || miss "origin remote is not App-vNext/Polly (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(BSD-3-Clause)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"BSD-3-Clause\"" package.json 2>/dev/null) \\
  && ok "license is BSD-3-Clause" \\
  || miss "license drift — was BSD-3-Clause at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "Directory.Build.props" \\
  && ok "Directory.Build.props" \\
  || miss "missing critical file: Directory.Build.props"
test -f "Directory.Build.targets" \\
  && ok "Directory.Build.targets" \\
  || miss "missing critical file: Directory.Build.targets"
test -f "Polly.slnx" \\
  && ok "Polly.slnx" \\
  || miss "missing critical file: Polly.slnx"
test -f ".github/workflows/build.yml" \\
  && ok ".github/workflows/build.yml" \\
  || miss "missing critical file: .github/workflows/build.yml"
test -f "README.md" \\
  && ok "README.md" \\
  || miss "missing critical file: README.md"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/App-vNext/Polly"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Polly is a .NET Standard resilience library that provides fluent APIs for expressing fault-handling policies (Retry, Circuit Breaker, Timeout, Bulkhead Isolation, Rate Limiting, Hedging, and Fallback) in a thread-safe manner. It solves the core problem of transient fault handling in distributed systems by allowing developers to compose multiple resilience strategies without boilerplate. Multi-package solution: Polly.slnx is a monorepo containing Polly.Core (core abstractions and strategies), Polly.Extensions (telemetry and DI support), and Polly.RateLimiting (System.Threading.RateLimiting integration). Build configuration centralized in Directory.Build.props/targets and Directory.Packages.props. GitHub Actions workflows in .github/workflows/ handle CI/CD, linting, mutation testing, and releases.

👥Who it's for

.NET backend engineers building microservices, APIs, and distributed systems who need robust handling of transient faults (network timeouts, temporary service unavailability) without implementing custom retry logic or circuit breaker patterns themselves.

🌱Maturity & risk

Polly is production-ready and mature. It has been in active development for 9+ years, maintains comprehensive CI/CD via GitHub Actions (.github/workflows/build.yml, code-ql.yml, mutation-tests.yml), extensive test coverage with mutation testing via Stryker, and is a .NET Foundation member project. Version 8.x represents a significant modernization with improved API design.

Risk is minimal: the project is well-maintained by a dedicated team with automated testing (mutation tests, CodeQL security scanning), however v8 introduced breaking API changes from v7, so upgrading requires migration effort. The codebase is large (~4.3M lines of C#) with multiple packages (Polly.Core, Polly.Extensions, Polly.RateLimiting) that must be kept in sync.

Active areas of work

The project is actively maintained with focus on v8 API refinement, security hardening (OpenSSF Scorecard badge present), and expanded strategy support (Hedging and Rate Limiting added recently). Dependabot is configured (.github/dependabot.yml) for automated dependency updates, and release.yml workflow suggests structured release cadence.

🚀Get running

Clone with git clone https://github.com/App-vNext/Polly.git && cd Polly. Use .NET SDK (check .config/dotnet-tools.json for tool versions). Build with dotnet build Polly.slnx. Run tests with dotnet test. No npm/PowerShell build scripts required for core development.

Daily commands: For development: dotnet build Polly.slnx then dotnet test Polly.slnx. For benchmarking: check bench/ directory structure. No standalone server—Polly is a library consumed by other projects via NuGet packages.

🗺️Map of the codebase

  • Directory.Build.props — Centralized property definitions and version management for all projects; defines SDK targets, package metadata, and build settings that all contributors must respect
  • Directory.Build.targets — Central build targets and post-build logic shared across all projects; critical for understanding how compilation, testing, and packaging work
  • Polly.slnx — Solution file defining all projects and their relationships; required entry point for understanding the overall architecture and project organization
  • .github/workflows/build.yml — Primary CI/CD pipeline defining build, test, and quality checks that all PRs must pass; essential for understanding contribution requirements
  • README.md — Project mission, scope, and core value propositions; every contributor must understand Polly's positioning as a resilience and transient-fault-handling library
  • CONTRIBUTING.md — Contribution guidelines, coding standards, and development workflow; mandatory reference for all potential contributors

🛠️How to make changes

Add a New Resilience Strategy

  1. Create strategy interface in src/Polly.Core/Resilience/ directory following the existing pattern (e.g., IRetryStrategy, ICircuitBreakerStrategy) (src/Polly.Core/Resilience/)
  2. Implement the strategy with PreExecute/OnResult/OnException handlers conforming to the ResilienceStrategy base class (src/Polly.Core/Resilience/)
  3. Create fluent builder extension in src/Polly.Core/Builders/ following AddRetry, AddCircuitBreaker patterns (src/Polly.Core/Builders/)
  4. Add comprehensive unit tests in src/Polly.Core.Tests/ mirroring the strategy structure (src/Polly.Core.Tests/)
  5. Add performance benchmark in bench/Polly.Core.Benchmarks/ to validate no performance regressions (bench/Polly.Core.Benchmarks/)

Extend an Existing Strategy with Options

  1. Modify the strategy's options class (e.g., RetryStrategyOptions) in src/Polly.Core/Resilience/ (src/Polly.Core/Resilience/)
  2. Update the strategy implementation to use new options in Execute/ExecuteAsync methods (src/Polly.Core/Resilience/)
  3. Update the fluent builder extension method to expose new options in src/Polly.Core/Builders/ (src/Polly.Core/Builders/)
  4. Add tests for new options in src/Polly.Core.Tests/ covering both sync and async paths (src/Polly.Core.Tests/)

Add Telemetry or Diagnostics Support

  1. Create telemetry event classes in src/Polly.Core/Telemetry/ following ResilienceEvent pattern (src/Polly.Core/Telemetry/)
  2. Inject ITelemetryListener into strategy and call OnXxxEvent methods at appropriate lifecycle points (src/Polly.Core/Resilience/)
  3. Register telemetry listener in ResiliencePipeline builder or individual strategy builders (src/Polly.Core/Builders/)
  4. Add telemetry tests validating events are fired in src/Polly.Core.Tests/Telemetry/ (src/Polly.Core.Tests/Telemetry/)

Create a Custom Predicate for Strategy Handling

  1. Define predicate logic in strategy options class (e.g., PredicateBuilder in RetryStrategyOptions) (src/Polly.Core/Resilience/)
  2. Use Predicate<TResult> delegate in strategy Execute/ExecuteAsync to decide if exception/result should be handled (src/Polly.Core/Resilience/)
  3. Expose predicate configuration in fluent builder (e.g., .HandleResult(), .Handle<TException>()) (src/Polly.Core/Builders/)
  4. Add tests for predicate evaluation in src/Polly.Core.Tests/Resilience/ (src/Polly.Core.Tests/Resilience/)

🔧Why these technologies

  • .NET Standard 1.1+ / .NET 5+ — Enables broad platform coverage from .NET Framework to latest .NET versions; allows library to be used across legacy and modern applications
  • Fluent builder pattern — Provides readable, discoverable, chainable API for composing resilience policies; avoids constructor parameter explosion and improves developer experience
  • Strategy pattern (ResilienceStrategy base class) — Allows composition of multiple independent resilience strategies in a pipeline; enables clean separation of concerns and easy testing of individual strategies
  • Async/await throughout — Ensures non-blocking I/O and scalability for high-throughput scenarios; aligns with modern .NET async patterns
  • Generic context passing — Allows strategies to share state and metadata without tight coupling; enables extensibility without modifying core strategy implementations

⚖️Trade-offs already made

  • Pipeline-based composition over traditional policy wrapping (v8+ vs v7)

    • Why: Addresses performance and flexibility concerns in v7; enables better control flow and cleaner composition
    • Consequence: v7 API incompatible with v8+; migration effort required for existing codebases, but new projects benefit from better performance and composability
  • Sync and async Execute methods rather than single async-only path

    • Why: Maintains backward compatibility and avoids async-over-sync anti-patterns; supports legacy synchronous code paths
    • Consequence: Code duplication between sync/async branches; more test coverage required; strategy implementations must support both paths
  • Telemetry via ITelemetryListener rather than event handlers

    • Why: Allows structured, typed telemetry events; integrates naturally with Application Insights and other observability platforms
    • Consequence: Requires explicit telemetry listener registration; not a default observable pattern unlike some competitors
  • Predicate-based exception/result matching over type-only filtering

    • Why: Provides granular control over which faults to handle (e.g., only retry on 5xx, not 4xx); enables context-aware handling decisions
    • Consequence: More flexible but slightly more verbose for simple cases; requires understanding of predicate composition

🚫Non-goals (don't propose these)

  • Automatic observability/tracing out of the box (requires manual ITelemetryListener integration)
  • Request deduplication or idempotency enforcement (strategies assume caller responsibility)
  • Distributed state sharing across service instances (circuit breaker state is in-process only)
  • Authentication or authorization (pure resilience layer, agnostic to auth concerns)
  • Data encryption or security beyond standard .NET framework protections

🪤Traps & gotchas

v8 API is significantly different from v7 (breaking changes)—documentation at www.thepollyproject.org covers v8, but Stack Overflow and older blog posts may reference v7. The monorepo has tight version coupling; packages must be released together. NuGet.config is present but dependency resolution should be verified locally. Benchmark suite in bench/ requires specific setup—not automatically run in standard build.

🏗️Architecture

💡Concepts to learn

  • Circuit Breaker Pattern — One of Polly's core strategies; prevents cascading failures by detecting and temporarily blocking requests to failing services
  • Token Bucket Rate Limiting — Polly.RateLimiting integrates System.Threading.RateLimiting; essential for controlling request rates and preventing resource exhaustion
  • Bulkhead Isolation — Polly strategy that partitions resources to prevent one failing component from exhausting all system resources
  • Fluent Builder Pattern — Polly's core API design paradigm; allows readable, chainable policy composition (e.g., retry.Wrap(circuitBreaker))
  • Exponential Backoff — Common retry strategy in Polly for spacing out retry attempts; reduces load on recovering services
  • Hedging Strategy — Polly v8 addition; launches parallel requests to reduce tail latencies in distributed systems (similar to Google's hedged requests)
  • Transient Fault Handling — Core problem Polly solves—distinguishing temporary failures (network blip) from permanent ones (invalid credentials) and responding appropriately
  • Steeltoe/steeltoe — Cloud-native .NET framework that uses Polly for resilience in microservices patterns and service discovery
  • grpc/grpc-dotnet — gRPC .NET implementation often uses Polly policies for resilient gRPC client calls in production
  • dotnet/runtime — Core .NET runtime; Polly targets .NET Standard and relies on System.Threading.RateLimiting and System.Diagnostics.DiagnosticSource from runtime
  • microsoft/resilience-module — Microsoft's official resilience patterns library for Semantic Kernel; Polly is a complementary choice for enterprise .NET resilience
  • App-vNext/Polly-Samples — Official examples and tutorial code demonstrating Polly policies in real-world scenarios (likely referenced in workflow/docs)

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for resilience strategy composition scenarios

The repo has extensive benchmark artifacts (bench/BenchmarkDotNet.Artifacts/) showing performance testing for composed strategies (CompositeComponentBenchmark, MultipleStrategiesBenchmark, ResiliencePipelineBenchmark), but there's no visible dedicated test suite validating correctness of real-world composition scenarios (e.g., Retry + CircuitBreaker + Timeout chains). This would ensure reliability when users combine multiple strategies and catch edge cases in state management across nested policies.

  • [ ] Create src/Polly.Tests/Resilience/CompositionIntegrationTests.cs
  • [ ] Add test cases for: Retry wrapping CircuitBreaker, CircuitBreaker wrapping Timeout, three-strategy chains with fault propagation
  • [ ] Test state isolation: verify one strategy's state doesn't leak to others in a pipeline
  • [ ] Add tests for exception handling order in composed pipelines
  • [ ] Verify telemetry (if present) correctly attributes failures to the right strategy in a composition

Add mutation testing baseline and CI validation in mutation-tests.yml workflow

The workflow file .github/workflows/mutation-tests.yml exists but mutation test results aren't visible in the repository structure. Mutation testing is critical for a resilience library to ensure test quality actually validates fault-handling behavior. Adding a baseline score requirement and CI gate would prevent test suite degradation as the library evolves.

  • [ ] Configure Stryker.NET (or similar mutation testing tool) in mutation-tests.yml with specific thresholds
  • [ ] Run mutation tests on core strategy implementations (Retry, CircuitBreaker, Timeout, RateLimiter, Hedging)
  • [ ] Store baseline mutation score in a tracked file (e.g., .github/mutation-baseline.json)
  • [ ] Add CI check to fail PR if mutation score drops below baseline
  • [ ] Document mutation testing results in CONTRIBUTING.md for contributors

Add missing documentation for Hedging strategy with examples and behavior guarantees

The README and file structure reference a Hedging strategy (visible in HedgingBenchmark), but there's no dedicated documentation file explaining how it works, when to use it, or its interaction with other strategies. Given this is a newer feature compared to Retry/CircuitBreaker, contributors and users need clear behavioral guarantees.

  • [ ] Create docs/strategies/hedging.md covering: definition, use cases, configuration options, example code
  • [ ] Document edge cases: hedging timeouts, hedging with rate limiters, cancellation behavior
  • [ ] Add cross-references to Hedging in README.md's feature list with link to docs
  • [ ] Include benchmark results from bench/BenchmarkDotNet.Artifacts/results/Polly.Core.Benchmarks.HedgingBenchmark-report-github.md in documentation
  • [ ] Add integration example in docs showing Hedging + CircuitBreaker pattern

🌿Good first issues

  • Add example code snippets to README.md demonstrating Hedging strategy usage (recently added but may lack example in root docs)
  • Expand mutation test coverage for Polly.RateLimiting integration tests to match Polly.Core coverage standards
  • Create runnable example project in examples/ demonstrating composed policies (Retry + Circuit Breaker + Timeout) with ASP.NET Core dependency injection via Polly.Extensions

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 647d683 — Bump meziantou.framework.nugetpackagevalidation.tool from 1.0.49 to 1.0.50 (#3062) (dependabot[bot])
  • 1b0aa3b — Bump GitHubActionsTestLogger from 3.0.3 to 3.0.4 (#3061) (dependabot[bot])
  • 79cd1a3 — Bump sign from 0.9.1-beta.26179.1 to 0.9.1-beta.26227.3 (#3064) (dependabot[bot])
  • 55436e8 — Bump ReportGenerator from 5.5.7 to 5.5.9 (#3063) (dependabot[bot])
  • 9bbc913 — Bump github/codeql-action from 4.35.2 to 4.35.3 (#3060) (dependabot[bot])
  • 9ecb719 — Bump DavidAnson/markdownlint-cli2-action from 23.1.0 to 23.2.0 (#3059) (dependabot[bot])
  • da4ae8f — Bump meziantou.framework.nugetpackagevalidation.tool from 1.0.47 to 1.0.49 (#3055) (dependabot[bot])
  • da4287f — Bump SonarAnalyzer.CSharp from 10.24.0.138807 to 10.25.0.139117 (#3058) (dependabot[bot])
  • cf24c21 — Bump ReportGenerator from 5.5.6 to 5.5.7 (#3057) (dependabot[bot])
  • 812c2e0 — Bump Microsoft.NET.Test.Sdk from 18.4.0 to 18.5.1 (#3056) (dependabot[bot])

🔒Security observations

The Polly codebase demonstrates strong security posture overall. The project includes comprehensive security policies with private vulnerability reporting procedures documented in SECURITY.md. No hardcoded secrets, credentials, or injection vulnerabilities were identified in the file structure. The project utilizes GitHub security features (security advisories, dependabot configuration, dependency review workflows, and CodeQL analysis). The only minor concern is the presence of the strong name key file in the repository, which is a best-practice issue rather than a critical vulnerability. The project follows .NET Foundation standards and maintains active security scanning through CI/CD workflows (code-ql.yml, dependency-review.yml, ossf-scorecard.yml).

  • Low · Strong Name Key File Present in Repository — Polly.snk. The file 'Polly.snk' (strong name key file) is present in the repository root. While this is a public key suitable for signing assemblies, storing key material in version control is not a security best practice, even if it's intended to be public. Fix: Consider storing the strong name key in a secure location outside the repository (e.g., Azure Key Vault, GitHub Secrets) and access it only during the build process via CI/CD pipelines.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · App-vNext/Polly — RepoPilot