{"id":21822774,"url":"https://github.com/kresil/kresil","last_synced_at":"2025-04-14T03:53:01.554Z","repository":{"id":247492247,"uuid":"765815842","full_name":"kresil/kresil","owner":"kresil","description":"Kotlin Multiplatform fault-tolerance library with Ktor integration","archived":false,"fork":false,"pushed_at":"2024-08-23T21:37:13.000Z","size":1707,"stargazers_count":4,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-27T17:51:57.318Z","etag":null,"topics":["circuit-breaker","fault-tolerance","kotlin-multiplatform","kotlin-multiplatform-library","ktor","resilience","resiliency-patterns","retry-strategies"],"latest_commit_sha":null,"homepage":"https://kresil.github.io/kresil/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kresil.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2024-03-01T17:11:55.000Z","updated_at":"2024-12-18T23:22:32.000Z","dependencies_parsed_at":"2024-07-16T22:35:31.965Z","dependency_job_id":null,"html_url":"https://github.com/kresil/kresil","commit_stats":null,"previous_names":["kresil/kresil"],"tags_count":0,"template":false,"template_full_name":"Kotlin/multiplatform-library-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kresil%2Fkresil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kresil%2Fkresil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kresil%2Fkresil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kresil%2Fkresil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kresil","download_url":"https://codeload.github.com/kresil/kresil/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248819363,"owners_count":21166474,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["circuit-breaker","fault-tolerance","kotlin-multiplatform","kotlin-multiplatform-library","ktor","resilience","resiliency-patterns","retry-strategies"],"created_at":"2024-11-27T17:17:33.222Z","updated_at":"2025-04-14T03:53:01.535Z","avatar_url":"https://github.com/kresil.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kresil - Kotlin Resilience Library \u003cimg src=\"./docs/imgs/kresil-logo.png\" align=\"right\" width=200 alt=\"\" /\u003e\n\nKresil is a [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html) library for fault-tolerance,\ninspired by [Resilience4j](https://resilience4j.readme.io/docs/getting-started) for Java\nand [Polly](https://github.com/App-vNext/Polly) for .NET. The library offers methods to enhance operations with\nresilience mechanisms in a functional style, using higher-order functions (decorators) while providing a concise API.\nAdditionally, Kresil offers extensions for [Ktor](https://ktor.io/) as plugins.\n\n## Resilience Mechanisms\n\n- 🔁 [Retry](#retry): Repeats failed executions;\n- ⛔ [Circuit Breaker](#circuit-breaker): Temporarily blocks possible failures.\n- ⏳ [Rate Limiter](#rate-limiter): Limits executions per period (🚧).\n\n\u003e [!NOTE]\n\u003e The symbol 🚧 means that the mechanism is under development.\n\n## Relevant Modules\n\n- 📁 [kresil-lib](kresil-lib/lib/README.md): Core module with the resilience mechanisms;\n- 📁 [ktor-client-plugins](ktor-client-plugins/shared/README.md): Mechanisms integration for [Ktor Client](https://ktor.io/docs/client-create-new-application.html) as plugins;\n- 📁 [ktor-server-plugins](ktor-server-plugins/shared/README.md): Mechanisms integration for [Ktor Server](https://ktor.io/docs/server-create-a-new-project.html) as plugins;\n- 📁 [ktor-plugins-demo](ktor-plugins-demo/README.md): Kotlin/JS applications for demonstrating the mechanisms, namely its integration with Ktor.\n\n## Retry\n\nA [Retry](https://learn.microsoft.com/en-us/azure/architecture/patterns/retry) is a reactive resilience mechanism\nthat can be used to retry an operation when it fails and the failure is a transient (temporary) fault. \nOperations can be decorated and executed on demand.\nA retry mechanism is initialized with a configuration that,\nthrough pre-configured policies, define its behaviour.\n\n### State Machine\n\nThe retry mechanism implements the following state machine:\n\n```\n                   +------------------+  retried once   +---------+\n+-----------+ ---\u003e | Returns Normally | --------------\u003e | Success |\n| Operation |      +------------------+                 +---------+\n|  Called   |      +-------+      +----------+\n+-----------+ ---\u003e | Fails | ---\u003e | Consults |\n      ^            +-------+      | Policies |\n      |                           +----------+\n      |                                |\n  +-------+      can use retry         |\n  | Retry | \u003c--------------------------|\n  +-------+                            |   expected\n                                       |   failure    +-------+\n                                       |------------\u003e | Error |\n                                       |              +-------+\n                    +---------+        |\n                    | Ignored | \u003c------|\n                    |  Error  |\n                    +---------+\n```\n\n### Usage\n\n```kotlin\n// use predefined retry policies\nval defaultRetry = Retry()\n\n// use custom policies\nval retry = Retry(\n    retryConfig {\n        maxAttempts = 5 // initial call + 4 retries\n        retryIf { it is NetworkError }\n        retryOnResult { it is \"success\" }\n        exponentialDelay(initialDelay = 500L.milliseconds, multiplier = 1.0, maxDelay = 1.minutes, randomizationFactor = 0.1)\n        // customDelay { attempt, context -\u003e ... }\n        // exceptionHandler { exception -\u003e ... }\n    }\n)\n\n// execute a supplier\nretry.executeSupplier {\n    // operation\n}\n\n// execute a supplier with context\nretry.executeCtxSupplier { ctx -\u003e\n    // operation\n}\n\n// decorate a supplier\nval decoratedSupplier = retry.decorateSupplier {\n    // operation\n}\n// and call it later\nval result = decoratedSupplier()\n\n// listen to specific events\nretry.onRetry { event -\u003e\n    // action\n}\n\n// listen to all events\nretry.onEvent { event -\u003e\n    // action\n}\n\n// cancel all listeners\nretry.cancelListeners()\n```\n\n## Circuit Breaker\n\nThe [Circuit Breaker](https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)\nis a **reactive** resilience mechanism\nthat can be used to protect a system component from overloading or failing.\nBy monitoring the health of the system, the circuit breaker can short-circuit\nexecution requests when it detects that the system component is not behaving as expected.\nAfter a configurable timeout,\nthe circuit breaker allows a limited number of test requests to pass through to see if the system has recovered.\nDepending on the test results, the circuit breaker can resume normal operation or continue to short-circuit requests.\nA circuit breaker is initialized with a configuration that,\nthrough pre-configured policies, define its behaviour.\n\n### State Machine\n\nThe circuit breaker implements the following state machine:\n\n```\n             failure rate exceeds\n +--------+  or equals threshold   +------+\n | Closed | ---------------------\u003e | Open |\n +--------+                        +------+\n     ^                               |  ^\n     |                         after |  |  failure rate\n     |                       timeout |  |  exceeds or\n     |                               |  |  equals threshold\n     |       failure rate            v  |\n     |       below threshold     +-----------+\n     |-------------------------- | Half-Open |\n                                 +-----------+\n```\n\n- In the **Closed** state, the circuit breaker allows calls to execute the underlying operation, while\nrecording the success or failure of these calls.\nWhen the failure rate exceeds a (configurable) threshold, the\ncircuit breaker transitions to the **Open** state.\n- In the **Open** state,\nthe circuit breaker rejects all received calls for a (configurable) amount of time and then transitions\nto the **HalfOpen** state.\n- In the **HalfOpen** state,\nthe circuit breaker allows a (configurable) number of calls to test if the underlying operation is still failing.\nAfter all calls have been attempted, the circuit breaker transitions back to the **Open** state if newly calculated\nfailure rate exceeds or equals the threshold; otherwise, it transitions to the **Closed** state.\n\n### Usage\n\n```kotlin\n// use predefined policies\nval defaultCircuitBreaker = CircuitBreaker()\n\n// use custom policies\nval circuitBreaker = CircuitBreaker(\n    circuitBreakerConfig {\n        failureRateThreshold = 0.5 // 50%\n        recordResultPredicate { it is \"success\" }\n        recordExceptionPredicate { it is NetworkError }\n        exponentialDelayInOpenState(initialDelay = 30.seconds, multiplier = 2.0, maxDelay = 10.minutes)\n        slidingWindow(size = 5, minimumThroughput = 2, type = COUNT_BASED)\n    }\n)\n\n// get the current state of the circuit breaker\nval observedState = circuitBreaker.currentState()\n\n// wire the circuit breaker\ncircuitBreaker.wire()\n\n// execute an operation under the circuit breaker\nval result = circuitBreaker.executeOperation {\n    // operation\n}\n\n// listen to specific events\ncircuitBreaker.onCallNotPermitted { event -\u003e\n    // action\n}\n\n// listen to all events\ncircuitBreaker.onEvent { event -\u003e\n    // action\n}\n\n// cancel all registered listeners\ncircuitBreaker.cancelListeners()\n\n// manually:\n// - override the circuit breaker state\ncircuitBreaker.transitionToOpen()\n// - reset the circuit breaker\ncircuitBreaker.reset()\n// - record an operation success\ncircuitBreaker.recordSuccess()\n// - record an operation failure\ncircuitBreaker.recordFailure()\n```\n\n## Rate Limiter\n\nThe [Rate Limiter](https://learn.microsoft.com/en-us/azure/architecture/patterns/rate-limiting) is a **proactive** resilience mechanism\nthat can be used to limit the number of requests that can be made to a system component, thereby controlling the consumption of resources and protecting the system from overloading.\nA rate limiter is initialized with a configuration that, through pre-configured policies, defines its behaviour.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkresil%2Fkresil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkresil%2Fkresil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkresil%2Fkresil/lists"}