{"id":20532468,"url":"https://github.com/joshdk/retry","last_synced_at":"2025-08-19T03:09:42.625Z","repository":{"id":44765969,"uuid":"223070527","full_name":"joshdk/retry","owner":"joshdk","description":"⏰ Rerun a command until it eventually succeeds, or doesn't!","archived":false,"fork":false,"pushed_at":"2022-12-21T03:49:22.000Z","size":49,"stargazers_count":30,"open_issues_count":2,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-14T06:37:44.540Z","etag":null,"topics":["go","golang","healthcheck","retry","retry-commands"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joshdk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-11-21T02:27:35.000Z","updated_at":"2025-04-10T01:00:43.000Z","dependencies_parsed_at":"2023-01-30T02:30:49.347Z","dependency_job_id":null,"html_url":"https://github.com/joshdk/retry","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/joshdk/retry","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshdk%2Fretry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshdk%2Fretry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshdk%2Fretry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshdk%2Fretry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joshdk","download_url":"https://codeload.github.com/joshdk/retry/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joshdk%2Fretry/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271093043,"owners_count":24697917,"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","status":"online","status_checked_at":"2025-08-19T02:00:09.176Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["go","golang","healthcheck","retry","retry-commands"],"created_at":"2024-11-16T00:15:06.353Z","updated_at":"2025-08-19T03:09:42.597Z","avatar_url":"https://github.com/joshdk.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Actions][github-actions-badge]][github-actions-link]\n[![License][license-badge]][license-link]\n[![Go Report Card][go-report-card-badge]][go-report-card-link]\n[![Godoc][godoc-badge]][godoc-link]\n[![Releases][github-release-badge]][github-release-link]\n\n# Retry\n\n⏰ Rerun a command until it eventually succeeds, or doesn't!\n\n## Installation\n\nPrebuilt binaries for several architectures can be found attached to any of the available [releases][github-release-link].\n\nFor Linux:\n```shell\nwget https://github.com/joshdk/retry/releases/download/v1.4.0/retry-linux-amd64.tar.gz\ntar -xf retry-linux-amd64.tar.gz\nsudo install retry /usr/bin/retry\n```\n\nFor Mac:\n```shell\nbrew tap joshdk/tap\nbrew install joshdk/tap/retry\n```\n\nA development version can also be built directly from this repository.\nRequires that you already have a functional Go toolchain installed.\n```shell\ngo install github.com/joshdk/retry@master\n```\n\n## Motivations\n\nI kept seeing folks write bespoke code to retry commands that were either flaky, or took time to succeed. This usually manifested as some sort of loop in bash, with a counter, and a return code check.\n\nSearching around, this doesn't seem to be an isolated problem, which has an even larger number of bespoke solutions. Take for example this handful of Stack Overflow threads:\n\n- [How to retry a command in Bash?](https://stackoverflow.com/questions/7449772/how-to-retry-a-command-in-bash)\n- [Retry a Bash command with timeout](https://stackoverflow.com/questions/12321469/retry-a-bash-command-with-timeout)\n- [How do I write a retry logic in script to keep retrying to run it upto 5 times?](https://unix.stackexchange.com/questions/82598/how-do-i-write-a-retry-logic-in-script-to-keep-retrying-to-run-it-upto-5-times)\n\nThese are perfectly legitimate questions, with many reasonable answers. The downside is that the solutions were usually specific to the question asked, and not always applicable to the broader problem.\n\nThis tool is an attempt to solve that broader problem. ⏰\n\n## Usage\n\n### Help!\n\n```bash\nUsage: retry [flags] command|url\n  -attempts int\n        maximum number of attempts (default 3)\n  -backoff\n        use exponential backoff when sleeping\n  -consecutive int\n        required number of back to back successes\n  -delay duration\n        initial delay period before tasks are run\n  -invert\n        wait for task to fail rather than succeed\n  -jitter duration\n        time range randomly added to sleep\n  -max-time duration\n        maximum total time (default 1m0s)\n  -quiet\n        silence all output\n  -sleep duration\n        time to sleep between attempts (default 5s)\n  -task-time duration\n        maximum time for a single attempt\n  -version\n        print the version \"v1.4.0\" and exit\n```\n\n### Running a command\n\nRetry will run a given command repeatedly, until it is deemed an overall success of failure. The conditions and limits for what determine success/failure can be tuned with command line flags.\n\nAs a special case, if a URL is given, retry will GET that URL and check for a 200 OK to be returned.\n\n### Limit attempts\n\nThe `-attempts` flag limits the maximum number of times a command can be run. A value of 0 allows unlimited attempts.\n\n\u003e Run `cat kubeconfig.yml` a maximum of 3 times, or less if the command succeeds earlier:\n\u003e\n\u003e ```bash\n\u003e $ retry -attempts=3 cat kubeconfig.yml\n\u003e ```\n\n### Limit task time\n\nThe `-task-time` flag limits the maximum time that a command can run for. A value of 0 allows unlimited time.\n\n\u003e Run `wget https://example.com`, but limit the command to only run for a maximum of 15 seconds.\n\u003e\n\u003e ```bash\n\u003e $ retry -task-time=15s wget https://example.com\n\u003e ```\n\n### Limit overall time\n\nThe `-max-time` flag limits the maximum total time that `retry` will run for. A value of 0 allows unlimited time.\n\n\u003e GET `https://example.com` repeatedly, but stop running after a total of 60 seconds.\n\u003e\n\u003e ```bash\n\u003e $ retry -max-time=60s https://example.com\n\u003e ```\n\n### Initial delay\n\nThe `-delay` flag inserts a one-time delay before initial starting to run commands.\n\n\u003e Run `wget https://example.com`, but start only after initially sleeping for 15 seconds.\n\u003e\n\u003e ```bash\n\u003e $ retry -delay=15s wget https://example.com\n\u003e ```\n\n### Sleep between attempts\n\nThe `-sleep` flag inserts a timed delay between command runs.\n\n\u003e Run `cat kubeconfig.yml`, but sleep for 15 seconds between runs.\n\u003e\n\u003e ```bash\n\u003e $ retry -sleep=15s cat kubeconfig.yml\n\u003e ```\n\n### Exponential backoff\n\nThe `-backoff` flag is used with `-sleep`, and will double the time delay between failed runs. Delay is reset after a successful run.\n\n\u003e Run `wget https://example.com`, sleeping for 15 seconds after the first failure, 30 seconds after the second failure, 1 minute after the third failure, etc...\n\u003e\n\u003e ```bash\n\u003e $ retry -sleep=15s -backoff wget https://example.com\n\u003e ```\n\n### Invert status\n\nThe `-invert` flag is used to flip a task's failure status. Successful task runs will become failures, and vice versa. Useful for when you want to retry a command until it fails.\n\n\u003e Run `curl https://example.com/health`, a maximum of 20 times, until it becomes unresponsive.\n\u003e\n\u003e ```bash\n\u003e $ retry -attempts=20 -invert curl https://example.com/health\n\u003e ```\n\n### Random jitter\n\nThe `-jitter` flag adds a random time range to the sleep duration. Jitter added on top of exponential backoff.\n\n\u003e Run `cat kubeconfig.yml`, sleep for 15 seconds minimum, plus a random 0-10 seconds between each run.\n\u003e\n\u003e ```bash\n\u003e $ retry -sleep=15s -jitter=10s cat kubeconfig.yml\n\u003e ```\n\n### Consecutive successes\n\nThe `-consecutive` flag requires a number of successful command runs to occur in a row in order to be considered successful. Useful for health checking a service that is inconsistent until if if fully started.\n\n\u003e GET `https://example.com`, requiring the command to be successful 3 times in a row.\n\u003e\n\u003e ```bash\n\u003e $ retry -consecutive=3 wget https://example.com\n\u003e ```\n\n### Be quiet!\n\nLastly, the `-quiet` flag silences all output (STDOUT and STDERR) from the command. Useful when running `retry` inside an `if`.\n\n\u003e Run `ls -R`, but swallow all output.\n\u003e\n\u003e ```bash\n\u003e $ retry -quiet ls -R\n\u003e ```\n\n### Altogether now\n\n\u003e Run `wget https://example.com` a maximum of **10** times. Each run can take a maximum of **15 seconds**, and a total of **2 minutes**. Delay for **15 seconds** before starting. Sleep for **5 seconds** between failures with exponential **backoff**. Lastly, require that the command succeeds **3 times** in a row.\n\u003e\n\u003e ```bash\n\u003e $ retry -attempts=10 -task-time=15s -max-time=2m -delay=15s -sleep=5s -backoff -consecutive=3 wget https://example.com\n\u003e```\n\n## License\n\nThis code is distributed under the [MIT License][license-link], see [LICENSE.txt][license-file] for more information.\n\n[github-actions-badge]:  https://github.com/joshdk/retry/workflows/build/badge.svg\n[github-actions-link]:   https://github.com/joshdk/retry/actions\n[github-release-badge]:  https://img.shields.io/github/release/joshdk/retry/all.svg\n[github-release-link]:   https://github.com/joshdk/retry/releases\n[go-report-card-badge]:  https://goreportcard.com/badge/github.com/joshdk/retry\n[go-report-card-link]:   https://goreportcard.com/report/github.com/joshdk/retry\n[godoc-badge]:           https://pkg.go.dev/badge/github.com/joshdk/retry/retry\n[godoc-link]:            https://pkg.go.dev/github.com/joshdk/retry/retry\n[license-badge]:         https://img.shields.io/badge/license-MIT-green.svg\n[license-file]:          https://github.com/joshdk/retry/blob/master/LICENSE.txt\n[license-link]:          https://opensource.org/licenses/MIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshdk%2Fretry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoshdk%2Fretry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoshdk%2Fretry/lists"}