{"id":45872776,"url":"https://github.com/dfds/dafda-resilience","last_synced_at":"2026-03-04T16:00:57.769Z","repository":{"id":340152844,"uuid":"1160906198","full_name":"dfds/dafda-resilience","owner":"dfds","description":null,"archived":false,"fork":false,"pushed_at":"2026-02-27T08:42:21.000Z","size":30,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-27T14:36:29.306Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dfds.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-18T14:09:09.000Z","updated_at":"2026-02-27T08:16:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dfds/dafda-resilience","commit_stats":null,"previous_names":["dfds/dafda-resilience"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/dfds/dafda-resilience","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfds%2Fdafda-resilience","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfds%2Fdafda-resilience/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfds%2Fdafda-resilience/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfds%2Fdafda-resilience/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dfds","download_url":"https://codeload.github.com/dfds/dafda-resilience/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dfds%2Fdafda-resilience/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30085790,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T15:40:14.053Z","status":"ssl_error","status_checked_at":"2026-03-04T15:40:13.655Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-27T10:57:32.405Z","updated_at":"2026-03-04T16:00:57.759Z","avatar_url":"https://github.com/dfds.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"﻿# Dafda.Resilience\n\nAdd resilience and fault tolerance to your Kafka consumers with [Polly](https://github.com/App-vNext/Polly)-powered strategies for [Dafda](https://github.com/dfds/dafda).\n\n## Overview\n\nDafda.Resilience is a lightweight extension library that brings enterprise-grade resilience patterns to Dafda's Kafka message consumers. Built on top of Polly, it enables you to handle transient failures, prevent cascading errors, and maintain high availability without blocking your message pipeline.\n\n## Features\n\nIt provides the existing features from Polly, such as retry, timeout, and circuit breaker, but also includes a unique \"Continue on Error\" strategy that allows your consumer to keep processing messages even when individual handlers fail.\n\n- 🔄 **Retry Strategies** — Automatically recover from transient failures with configurable backoff\n- ⏱️ **Timeout Control** — Prevent long-running handlers from blocking your message pipeline\n- 🔌 **Circuit Breaker** — Fail fast and protect downstream services when errors exceed thresholds\n- ✅ **Continue on Error** — Keep processing messages even when individual handlers fail\n- 🎯 **Composable Pipelines** — Combine multiple Polly strategies for sophisticated error handling\n- 🔧 **Seamless Integration** — Works naturally with Dafda's existing configuration API\n\n## Installation\n\n```bash\ndotnet add package Dafda.Resilience\n```\n\n**Requirements:**\n- .NET 8.0 or later\n- Dafda 1.1.0 or later\n- Polly.Core 8.6.5 or later\n\n## Quick Start\n\n### Basic Retry Configuration\n\nAdd retry logic to handle transient failures:\n\n```csharp\n// Register the resilience pipeline\nservices.AddResiliencePipeline(\"retry-pipeline\", builder =\u003e\n{\n    builder.AddRetry(new()\n    {\n        MaxRetryAttempts = 3,\n        Delay = TimeSpan.FromSeconds(1)\n    });\n});\n\n// Use it in your consumer\nservices.AddConsumer(options =\u003e\n{\n    options.WithResiliencePipeline(\"retry-pipeline\");\n});\n```\n\n### Continue on Error\n\nKeep processing messages even when handlers fail:\n\n```csharp\n// Register the resilience pipeline\nservices.AddResiliencePipeline(\"continue-on-error\", builder =\u003e\n{\n    builder.AddContinueOnError(new()\n    {\n        OnError = (ex, context) =\u003e Console.WriteLine($\"Failed: {ex.Message}\"),\n        ShouldHandle = ex =\u003e ex is not OperationCanceledException\n    });\n});\n\n// Use it in your consumer\nservices.AddConsumer(options =\u003e\n{\n    options.WithResiliencePipeline(\"continue-on-error\");\n});\n```\n\n### Combining Strategies\n\nCombine retry with continue-on-error to ensure your consumer keeps processing messages:\n\n```csharp\n// Register the resilience pipeline\nservices.AddResiliencePipeline(\"robust-pipeline\", builder =\u003e\n{\n    builder.AddContinueOnError(new()\n    {\n        OnError = (ex, context) =\u003e logger.LogError(ex, \"Processing failed\"),\n        ShouldHandle = ex =\u003e ex is not OperationCanceledException\n    })\n    .AddRetry(new()\n    {\n        MaxRetryAttempts = 3,\n        Delay = TimeSpan.FromSeconds(1)\n    });\n});\n\n// Use it in your consumer\nservices.AddConsumer(options =\u003e\n{\n    options.WithResiliencePipeline(\"robust-pipeline\");\n});\n```\n\n\u003e ⚠️ **Strategy Order Matters:** Add `AddContinueOnError` **first** (outermost), then retry strategies. This ensures retries execute before the exception is swallowed.\n\n### Reusing Pipelines Across Consumers\n\nRegister a resilience pipeline once and use it for multiple consumers:\n\n```csharp\n// Register the resilience pipeline once\nservices.AddResiliencePipeline(\"shared-pipeline\", builder =\u003e\n{\n    builder.AddContinueOnError(new())\n    .AddRetry(new())\n    .AddTimeout(new());\n});\n\n// Use the same pipeline for multiple consumers\nservices.AddConsumer(options =\u003e\n{\n    options.WithResiliencePipeline(\"shared-pipeline\");\n});\n\nservices.AddConsumer(options =\u003e\n{\n    options.WithResiliencePipeline(\"shared-pipeline\");\n});\n```\n\n## Resilience Strategies\n\nThis only provides a brief overview of the available strategies. For detailed configuration options and examples, please refer to the [Polly Documentation](https://www.pollydocs.org/strategies/index.html).\n\n### Continue on Error\n\nThe `ContinueOnError` strategy allows your consumer to keep processing subsequent messages even when a handler fails. This is critical for high-throughput scenarios where one bad message shouldn't block the entire pipeline.\n\n**Basic Configuration:**\n\n```csharp\nbuilder.AddContinueOnError(new()\n{\n    OnError = (ex, context) =\u003e logger.LogError(ex, \"Message processing failed\"),\n    ShouldHandle = ex =\u003e ex is not OperationCanceledException\n});\n```\n\n**Advanced Configuration:**\n\n```csharp\nservices.AddResiliencePipeline(\"MyPipeline\", (builder, context) =\u003e\n{\n    builder.AddContinueOnError(new()\n    {\n        OnError = (ex, msgContext) =\u003e \n        {\n            var logger = context.GetRequiredService\u003cILogger\u003e();\n            var deadLetterQueue = context.GetRequiredService\u003cIDeadLetterQueue\u003e();\n\n            logger.LogError(ex, \"Message processing failed\");\n            deadLetterQueue.SendAsync(failedMessage, ex);\n        },\n        ShouldHandle = ex =\u003e \n        {\n            // Return true to swallow and continue\n            // Return false to propagate and stop\n            return ex is not OperationCanceledException;\n        }\n    });\n}\n```\n\n### Retry\n\nAutomatically retry failed message processing:\n\n```csharp\nbuilder.AddRetry(new()\n{\n    MaxRetryAttempts = 3,\n    Delay = TimeSpan.FromSeconds(1)\n});\n```\n\n**With exponential backoff:**\n\n```csharp\nbuilder.AddRetry(new()\n{\n    MaxRetryAttempts = 5,\n    BackoffType = DelayBackoffType.Exponential,\n    Delay = TimeSpan.FromSeconds(2)\n});\n```\n\n**Handle specific exceptions:**\n\n```csharp\nbuilder.AddRetry(new()\n{\n    MaxRetryAttempts = 3,\n    Delay = TimeSpan.FromSeconds(1),\n    ShouldHandle = new PredicateBuilder()\n        .Handle\u003cHttpRequestException\u003e()\n        .Handle\u003cTimeoutException\u003e()\n});\n```\n\n### Timeout\n\nPrevent long-running message handlers from blocking your consumer:\n\n```csharp\nbuilder.AddTimeout(TimeSpan.FromSeconds(30));\n```\n\n### Circuit Breaker\n\nFail fast and protect downstream services when error rates exceed thresholds:\n\n```csharp\nbuilder.AddCircuitBreaker(new()\n{\n    FailureRatio = 0.5,          // Break after 50% failure rate\n    MinimumThroughput = 10,      // At least 10 operations before breaking\n    BreakDuration = TimeSpan.FromMinutes(1)\n});\n```\n\n### Multiple Strategies\n\nCombine multiple strategies for robust error handling:\n\n```csharp\n// Register a comprehensive resilience pipeline\nservices.AddResiliencePipeline(\"comprehensive-pipeline\", builder =\u003e\n{\n    builder.AddContinueOnError(new ContinueOnErrorStrategyOptions\n    {\n        OnError = (ex, context) =\u003e logger.LogError(ex, \"Processing failed after all retries\")\n    })\n    .AddRetry(new()\n    {\n        MaxRetryAttempts = 5,\n        BackoffType = DelayBackoffType.Exponential,\n        Delay = TimeSpan.FromSeconds(2)\n    })\n    .AddTimeout(TimeSpan.FromSeconds(30))\n    .AddCircuitBreaker(new()\n    {\n        FailureRatio = 0.5,\n        MinimumThroughput = 10,\n        BreakDuration = TimeSpan.FromMinutes(1)\n    });\n});\n\n// Use it in your consumer\nservices.AddConsumer(options =\u003e\n{\n    options.WithResiliencePipeline(\"comprehensive-pipeline\");\n});\n```\n\n## How It Works\n\n### Pipeline Execution Flow\n\n```\n┌─────────────────┐\n│ Message Received│\n└────────┬────────┘\n         │\n         ▼\n┌─────────────────┐\n│ ContinueOnError │ ← Swallows final exceptions\n└────────┬────────┘\n         │\n         ▼\n┌─────────────────┐\n│     Retry       │ ← Retries on transient failures\n└────────┬────────┘\n         │\n         ▼\n┌─────────────────┐\n│    Timeout      │ ← Cancels slow operations\n└────────┬────────┘\n         │\n         ▼\n┌─────────────────┐\n│ Circuit Breaker │ ← Breaks circuit on threshold\n└────────┬────────┘\n         │\n         ▼\n┌─────────────────┐\n│ Message Handler │\n└─────────────────┘\n```\n\n## Best Practices\n\n### Strategy Ordering\n\nOrder strategies from **outermost to innermost** based on your desired behavior:\n\n```csharp\n// ✅ Correct order\nbuilder.AddContinueOnError(options);  // Outermost - handles final failures\nbuilder.AddRetry(retryOptions);       // Middle - attempts recovery\nbuilder.AddTimeout(timeout);          // Innermost - controls individual attempts\n```\n\n```csharp\n// ❌ Wrong order - retry will never execute\nbuilder.AddRetry(retryOptions);    \nbuilder.AddContinueOnError(options);  // Swallows exceptions before retry\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit issues or pull requests.\n\n## License\n\nThis project is maintained by [DFDS](https://github.com/dfds).\n\n## Related Projects\n\n- [Dafda](https://github.com/dfds/dafda) — Lightweight Kafka library for .NET\n- [Polly](https://github.com/App-vNext/Polly) — Resilience and transient-fault-handling library\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfds%2Fdafda-resilience","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdfds%2Fdafda-resilience","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdfds%2Fdafda-resilience/lists"}