PollyAzureEventHub 1.0.0

dotnet add package PollyAzureEventHub --version 1.0.0
                    
NuGet\Install-Package PollyAzureEventHub -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PollyAzureEventHub" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PollyAzureEventHub" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="PollyAzureEventHub" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PollyAzureEventHub --version 1.0.0
                    
#r "nuget: PollyAzureEventHub, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PollyAzureEventHub@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PollyAzureEventHub&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=PollyAzureEventHub&version=1.0.0
                    
Install as a Cake Tool

PollyAzureEventHub

NuGet NuGet Downloads CI License: MIT

Polly v8 resilience for Azure.Messaging.EventHubs — add retry, timeout, and circuit-breaker to any Event Hubs producer operation in two lines.

var producer = new EventHubProducerClient(connectionString, "my-hub");

var resilient = producer.WithPolly(pipeline => pipeline
    .AddRetry(new RetryStrategyOptions
    {
        MaxRetryAttempts = 3,
        Delay = TimeSpan.FromSeconds(2),
        BackoffType = DelayBackoffType.Exponential,
        UseJitter = true,
        ShouldHandle = EventHubsTransientErrors.IsTransient,
    })
    .AddTimeout(TimeSpan.FromSeconds(30)));

using var batch = await resilient.CreateBatchAsync();
batch.TryAdd(new EventData("hello"));
await resilient.SendAsync(batch);

Why PollyAzureEventHub?

Azure Event Hubs is a mission-critical ingestion pipeline — dropped events mean lost data. EventHubsException.IsTransient tells you exactly which errors are safe to retry; this library wires that directly into Polly v8:

Problem Solution
EventHubsException where IsTransient = true (throttling, service busy, connection dropped) Caught by EventHubsTransientErrors.IsTransient
TimeoutException — service took too long to respond Caught by EventHubsTransientErrors.IsTransient
TaskCanceledException — network timeout during transit Caught by EventHubsTransientErrors.IsTransient
Non-retriable errors (bad request, auth failure) Not retried — IsTransient = false is respected
Cascading failures during an outage Wrap with AddCircuitBreaker

Installation

dotnet add package PollyAzureEventHub
dotnet add package Polly.Core

Quick-start

1. Manual wiring

using Azure.Messaging.EventHubs;
using Azure.Messaging.EventHubs.Producer;
using Polly;
using Polly.Retry;

var producer = new EventHubProducerClient(connectionString, "telemetry");

var resilient = producer.WithPolly(p => p
    .AddRetry(new RetryStrategyOptions
    {
        MaxRetryAttempts = 3,
        Delay = TimeSpan.FromSeconds(2),
        BackoffType = DelayBackoffType.Exponential,
        UseJitter = true,
        ShouldHandle = EventHubsTransientErrors.IsTransient,
    }));

// Send a batch
using var batch = await resilient.CreateBatchAsync();
foreach (var reading in sensorReadings)
    batch.TryAdd(new EventData(JsonSerializer.SerializeToUtf8Bytes(reading)));

await resilient.SendAsync(batch);

2. Dependency injection

// Program.cs / Startup.cs
builder.Services.AddPollyAzureEventHub(
    connectionString,
    "telemetry",
    pipeline => pipeline
        .AddRetry(new RetryStrategyOptions
        {
            MaxRetryAttempts = 3,
            Delay = TimeSpan.FromSeconds(2),
            BackoffType = DelayBackoffType.Exponential,
            UseJitter = true,
            ShouldHandle = EventHubsTransientErrors.IsTransient,
        })
        .AddTimeout(TimeSpan.FromSeconds(30)));

// Inject ResilientEventHubProducerClient into your services
public class TelemetryIngester(ResilientEventHubProducerClient producer)
{
    public async Task SendAsync(IEnumerable<Reading> readings, CancellationToken ct)
    {
        using var batch = await producer.CreateBatchAsync(ct);
        foreach (var r in readings)
            batch.TryAdd(new EventData(JsonSerializer.SerializeToUtf8Bytes(r)));
        await producer.SendAsync(batch, ct);
    }
}

3. Bring your own client (DI overload)

builder.Services.AddSingleton(new EventHubProducerClient(
    fullyQualifiedNamespace,
    "telemetry",
    new DefaultAzureCredential()));

builder.Services.AddPollyAzureEventHub(pipeline => pipeline
    .AddRetry(new RetryStrategyOptions
    {
        MaxRetryAttempts = 5,
        ShouldHandle = EventHubsTransientErrors.IsTransient,
    }));

Transient error reference

// Use in any Polly strategy:
ShouldHandle = EventHubsTransientErrors.IsTransient
Condition Why it's transient
EventHubsException (IsTransient = true) Service throttling, quota exceeded, brief outage — SDK-designated as safe to retry
EventHubsException (IsTransient = false) Auth failure, bad request — not retried
TimeoutException Operation timed out waiting for service response
TaskCanceledException Network-level cancellation or timeout

Key differentiator: EventHubsException.IsTransient is set by the Azure SDK team — this library exposes it directly as a Polly predicate, so your retry logic is always in sync with the SDK's own classification.

Advanced pipelines

Full production pipeline with observability

producer.WithPolly(p => p
    .AddTimeout(TimeSpan.FromSeconds(60))
    .AddRetry(new RetryStrategyOptions
    {
        MaxRetryAttempts = 5,
        Delay = TimeSpan.FromSeconds(1),
        BackoffType = DelayBackoffType.Exponential,
        UseJitter = true,
        ShouldHandle = EventHubsTransientErrors.IsTransient,
        OnRetry = args =>
        {
            logger.LogWarning("Event Hubs retry {Attempt} after {Delay}ms — {Exception}",
                args.AttemptNumber, args.RetryDelay.TotalMilliseconds, args.Outcome.Exception?.Message);
            return ValueTask.CompletedTask;
        },
    })
    .AddCircuitBreaker(new CircuitBreakerStrategyOptions
    {
        FailureRatio = 0.5,
        SamplingDuration = TimeSpan.FromSeconds(30),
        MinimumThroughput = 10,
        BreakDuration = TimeSpan.FromSeconds(30),
        ShouldHandle = EventHubsTransientErrors.IsTransient,
    }));

Sending with partition key

var options = new SendEventOptions { PartitionKey = deviceId };
await resilient.SendAsync(events, options, cancellationToken);

Arbitrary operations via ExecuteAsync

var partitionProps = await resilient.ExecuteAsync(
    (c, ct) => c.GetPartitionPropertiesAsync("0", ct));

API reference

ResilientEventHubProducerClient

Member Description
Inner The underlying EventHubProducerClient
CreateBatchAsync(ct) Creates a batch through the pipeline
CreateBatchAsync(options, ct) Creates a batch with options through the pipeline
SendAsync(batch, ct) Sends a batch through the pipeline
SendAsync(events, ct) Sends a collection of events through the pipeline
SendAsync(events, options, ct) Sends events with partition options through the pipeline
ExecuteAsync<T>(operation, ct) Runs any EventHubProducerClient operation through the pipeline

EventHubsTransientErrors

Member Description
IsTransient PredicateBuilder for transient EventHubsException, TimeoutException, TaskCanceledException

Extension methods

Method Description
client.WithPolly(pipeline) Wraps an EventHubProducerClient with a pre-built ResiliencePipeline
client.WithPolly(configure) Builds a pipeline inline and wraps the client

DI extensions

Method Description
services.AddPollyAzureEventHub(configure) Registers ResiliencePipeline + ResilientEventHubProducerClient (requires EventHubProducerClient already in DI)
services.AddPollyAzureEventHub(connectionString, hubName, configure) Registers EventHubProducerClient, pipeline, and resilient client

Target frameworks

Framework Supported
.NET 6
.NET 8
.NET 9
Package Description
PollyAzureServiceBus Polly v8 for Azure Service Bus
PollyAzureBlob Polly v8 for Azure Blob Storage
PollyAzureKeyVault Polly v8 for Azure Key Vault
PollyCosmosDb Polly v8 for Azure Cosmos DB
PollyKafka Polly v8 for Confluent.Kafka
PollyRabbitMQ Polly v8 for RabbitMQ
PollySignalR Polly v8 for SignalR
PollyRedis Polly v8 for StackExchange.Redis
PollyElasticsearch Polly v8 for Elastic.Clients.Elasticsearch
PollyEFCore Polly v8 for Entity Framework Core
PollyDapper Polly v8 for Dapper
PollyMongo Polly v8 for MongoDB
PollyNpgsql Polly v8 for Npgsql (PostgreSQL)
PollySqlClient Polly v8 for Microsoft.Data.SqlClient
PollyGrpc Polly v8 for gRPC
PollyOpenAI Polly v8 for OpenAI .NET SDK
PollyMediatR Polly v8 for MediatR
PollyHealthChecks Polly v8 for ASP.NET Core Health Checks
PollyBackoff Polly v8 backoff helpers

License

MIT © Justin Bannister

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 48 6/24/2026

1.0.0: Initial release. ResilientEventHubProducerClient wraps EventHubProducerClient in a Polly v8 ResiliencePipeline. Includes EventHubsTransientErrors helper with pre-built ShouldHandle predicate using EventHubsException.IsTransient, plus TimeoutException and TaskCanceledException. Supports net6.0, net8.0, and net9.0.