{"id":15043836,"url":"https://github.com/ravichaturvedi/retrier","last_synced_at":"2026-02-11T10:32:08.625Z","repository":{"id":57734610,"uuid":"96040406","full_name":"ravichaturvedi/retrier","owner":"ravichaturvedi","description":"Java8 library to simplify retries","archived":false,"fork":false,"pushed_at":"2018-04-13T03:20:14.000Z","size":99,"stargazers_count":1,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-13T03:37:11.040Z","etag":null,"topics":["cloud","distributed-systems","java-8","lambda","microservices","resilent"],"latest_commit_sha":null,"homepage":"https://ravichaturvedi.github.io/retrier","language":"Java","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/ravichaturvedi.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}},"created_at":"2017-07-02T18:02:13.000Z","updated_at":"2023-04-02T10:38:23.000Z","dependencies_parsed_at":"2022-09-11T16:40:52.033Z","dependency_job_id":null,"html_url":"https://github.com/ravichaturvedi/retrier","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ravichaturvedi/retrier","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravichaturvedi%2Fretrier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravichaturvedi%2Fretrier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravichaturvedi%2Fretrier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravichaturvedi%2Fretrier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ravichaturvedi","download_url":"https://codeload.github.com/ravichaturvedi/retrier/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ravichaturvedi%2Fretrier/sbom","scorecard":{"id":763090,"data":{"date":"2025-08-11","repo":{"name":"github.com/ravichaturvedi/retrier","commit":"e35aad6038d13feba5db78d1796b9b0bad5453bb"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 1/23 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'","Warn: branch protection not enabled for branch 'feature/0.2'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 12 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-22T23:55:56.229Z","repository_id":57734610,"created_at":"2025-08-22T23:55:56.229Z","updated_at":"2025-08-22T23:55:56.229Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29332277,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T06:13:03.264Z","status":"ssl_error","status_checked_at":"2026-02-11T06:12:55.843Z","response_time":97,"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":["cloud","distributed-systems","java-8","lambda","microservices","resilent"],"created_at":"2024-09-24T20:49:39.951Z","updated_at":"2026-02-11T10:32:08.607Z","avatar_url":"https://github.com/ravichaturvedi.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Retrier\n\n[![Build Status](https://travis-ci.org/ravichaturvedi/retrier.svg?branch=master)](https://travis-ci.org/ravichaturvedi/retrier)\n\nJava library to simplify retries of any function or code block (piece of code wrapped in lambda expression) without \nchanging the execution flow from developer perspective. They can rely on the return value of the function/code block in retry, etc..\n\n## Getting Started\n\nAdd the following `maven` dependency to your project `pom.xml`:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.ravichaturvedi\u003c/groupId\u003e\n    \u003cartifactId\u003eretrier\u003c/artifactId\u003e\n    \u003cversion\u003e0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n```java\nimport static io.github.ravichaturvedi.retrier.Retry.*;\n\n// Retrying on some piece of code which may return value or may throw exception.\n// Result will be of same type as returned by the lambda expression.\nMap\u003cString, String\u003e result = retry(() -\u003e {\n    // some operation which may throw exception\n    return new HashMap\u003cString, String\u003e();\n});\n\n\n// Retrying on some piece of code which doesn't return any value but can throw exception\nretry(() -\u003e {\n    // some operation which may throw exception\n});\n```\n\n* `Retry.retry` is using the default `Retrier` with Retry Count `3`, Exponential Backoff initial Delay of `1 second` and retry timeout duration of `15 second`. \n\n## Background\nGenerally, we call an external system/service using some RPC mechanism (REST/GRPC/etc..) but we immediately inform about the failure to the client/user.\nBut in case if it would have been some transient failure (network issue/connectivity issue/etc..) then we could have retried and get success next time.\nThat would be a much nice experience to the client/user calling your service.\n\nThese kind of situation occurs in distributed system, microservice, mobile application and even within the same process space if some method/code block is throwing exception transiently.\n\nThere are many strategies to deal with retries and generally due to the induced complexity in the code, developer tends not to do it in while writing the first version of the program/software. \nThis library fills that gap by providing a library, which in turn provides an elegant abstraction to deal with retries of any function/code-block.\n\nThe whole idea behind building thins library is to encourage developers to build more resilient systems.\n\n## Features\n* Retry on any function/code-block which returns value (of any type!) and may throw RuntimeException not declared as method signature.\n* Retry on any function/code-block which does not returns any value and may throw RuntimeException not declared as method signature.\n* Retries can capture the context by using lambda expression so function can have any number of arguments, passed in by the captured context in lambda expression.\n* Retry upto number of times.\n* Retry upto the timeout expires.\n* Retry with exponential backoff delay.\n* Retry with exponential backoff with max backoff delay.\n* Retry on any Exception type so if the provided exception type `isAssignableFrom` the thrown exception then retry will happen.\n* Retry but execute some piece of code when specific exception occurs (check is based on `isAssignableFrom`), like populate the data etc.\n* Retry on nested exception wrapped within the other exception (as returned by getCause() method).\n* Retry can have constraint from all the above permutation/combination.\n* Retry returns back the exact same exception as thrown inside the retry block.\n\n## Drawbacks\n* Returned exception will be captured into `Exception` type, so user need to handle that if required.\nBut as the actual exception gets propogated so should be easily taken care of.\n\n## Safety\nKeep in mind any side effects that may occur if the operation is executed multiple times.\nIn general, the it is safe to retry only [idempotent](https://en.wikipedia.org/wiki/Idempotence) operations.\nIdempotent operations are those which do not change the result when applied repeatedly.\n\nExamples of `idempotent` operation:\n* Put a value in some store corresponding to a key without any condition.\n* Read operations that have no side effect\n* HTTP GET or PUT (typically)\n\nExamples of `non-idempotent` operation:\n* Increment a counter\n* HTTP POST (typically)\n\n## Usages \nSpecifying below some typical retry use cases covered by the Retrier.\n\nAssuming there are methods named `foo` and `bar` that throws `Exception` and following imports are in place:\n\n```java\nimport static io.github.ravichaturvedi.retrier.Retriers.*;\nimport static io.github.ravichaturvedi.retrier.Retry.*;\n\nvoid foo() throws Exception;\n\u003cT\u003e T bar(T) throws Exception;\n```\n\n1. Retry number of times\n\n```java\nRetrier retrier = create(withRetryCount(3));\n\n// Retring in lambda that doesn't return anything\nretrier.retry(on(Exception.class), () -\u003e foo());\n\n// Retrying on lambda that returns integer. \nint result = retrier.retry(on(Exception.class), () -\u003e bar(2));\n```\n\n2. Retry number of times until timeout expires\n\n```java\nRetrier retrier = create(withRetryCount(3), \n                        withTimeout(Duration.of(15, ChronoUnit.SECONDS)));\n                        \n// Retring in lambda that doesn't return anything                        \nretrier.retry(on(Exception.class), () -\u003e foo());\n\n// Retrying on lambda that returns Object. \nObject result = retrier.retry(on(Exception.class), () -\u003e bar(new Object()));\n```\n\n3. Retry unlimited number of times until timeout expires.\n\n```java\nRetrier retrier = create(withTimeout(Duration.of(15, ChronoUnit.SECONDS)));\n\n// Retring in lambda that doesn't return anything \nretrier.retry(on(Exception.class), () -\u003e foo());\n\n// Retrying on lambda that returns a map. \nMap\u003cString, String\u003e result = retrier.retry(on(Exception.class), () -\u003e {\n    return new HashMap\u003cString, String\u003e();\n});\n```\n\n4. Retry unlimited number of times with exponential backoff delay.\n\n```java\nRetrier retrier = create(withExpBackoff(Duration.of(3, ChronoUnit.SECONDS))));\n\n// Retring in lambda that doesn't return anything \nretrier.retry(on(Exception.class), () -\u003e foo());\n\n// Retrying on lambda that returns a long. \nlong result = retrier.retry(on(Exception.class), () -\u003e {\n    return 2L;\n});\n```\n\n5. Retry unlimited number of times with exponential backoff delay and max backoff delay.\n\n```java\nRetrier retrier = create(withExpBackoff(Duration.of(3, ChronoUnit.SECONDS), Duration.of(9, ChronoUnit.SECONDS)));\n\n// Retring in lambda that doesn't return anything \nretrier.retry(on(Exception.class), () -\u003e foo());\n\n// Retrying on lambda that returns a long. \nlong result = retrier.retry(on(Exception.class), () -\u003e {\n    return 2L;\n});\n```\n\n6. Retry unlimited number of times with exponential backoff delay and max backoff delay but on nested exception.\n\n```java\nRetrier retrier = create(withExpBackoff(Duration.of(3, ChronoUnit.SECONDS), Duration.of(9, ChronoUnit.SECONDS)));\n\n// Retring in lambda that doesn't return anything \nretrier.retry(onNested(IllegalArgumentException.class), () -\u003e foo());\n\n// Retrying on lambda that returns a long. \nlong result = retrier.retry(onNested(IllegalArgumentException.class), () -\u003e {\n    return 2L;\n});\n```\n\n7. Retry number of times with timeout and exponential backoff with initial delay.\n\n```java\nRetrier retrier = create(withRetryCount(3), \n                        withTimeout(Duration.of(15, ChronoUnit.SECONDS)),\n                        withExpBackoff(Duration.of(3, ChronoUnit.SECONDS)));\n              \n// Retring in lambda that doesn't return anything                         \nretrier.retry(on(Exception.class), () -\u003e foo());\n\n// Retrying on lambda that returns a long.\nlong result = retrier.retry(on(Exception.class), () -\u003e bar(2L));\n```\n\n8. Retry number of times with timeout, exponential backoff with initial delay and max backoff delay.\n\n```java\nRetrier retrier = create(withRetryCount(3), \n                        withTimeout(Duration.of(15, ChronoUnit.SECONDS)),\n                        withExpBackoff(Duration.of(3, ChronoUnit.SECONDS), Duration.of(9, ChronoUnit.SECONDS)));\n                        \nretrier.retry(on(Exception.class), () -\u003e foo());\nMap\u003cString, String\u003e result = retrier.retry(on(Exception.class), () -\u003e bar(new HashMap\u003cString, String\u003e()));\n```\n\n9. Retry number of times with timeout, exponential backoff with initial delay, max backoff delay and trace to see how retrier itself is working.\n\n   Since withTrace accepts any lambda which takes `java.lang.String` as only parameter, so can be hooked with any type of logging infrastructure.\n\n```java\nRetrier retrier = create(withRetryCount(3), \n                        withTimeout(Duration.of(15, ChronoUnit.SECONDS)),\n                        withExpBackoff(Duration.of(3, ChronoUnit.SECONDS), Duration.of(9, ChronoUnit.SECONDS)),\n                        withTrace(System.out::println));\n                        \nretrier.retry(on(Exception.class), () -\u003e foo());\nSet\u003cString\u003e result = retrier.retry(on(Exception.class), () -\u003e bar(new HashSet\u003cString\u003e()));\n```\n\n10. Retry number of times with timeout, exponential backoff with initial delay, max backoff delay and trace to see how retrier itself is working.\n   Also if specific exception occurs then execute some piece of code.\n\n   Since withTrace accepts any lambda which takes `java.lang.String` as only parameter, so can be hooked with any type of logging infrastructure.\n\n```java\nRetrier retrier = create(withRetryCount(3), \n                        withTimeout(Duration.of(15, ChronoUnit.SECONDS)),\n                        withExpBackoff(Duration.of(3, ChronoUnit.SECONDS), Duration.of(9, ChronoUnit.SECONDS)),\n                        withTrace(System.out::println));\n                        \nretrier.retry(() -\u003e {\n    foo();\n}, on(on(IllegalStateException.class), on(IllegalArgumentException.class, ()-\u003e {\n       // Some handling of exception\n})));\n\nretrier.retry(() -\u003e {\n    return bar();\n}, on(on(IllegalStateException.class), on(IllegalArgumentException.class, ()-\u003e {\n       // Some handling of exception\n})));\n```\n\n\n## Credits\n* This library is inspired by my previous experience in dealing with microservices and handling failures.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fravichaturvedi%2Fretrier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fravichaturvedi%2Fretrier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fravichaturvedi%2Fretrier/lists"}