https://github.com/dbohdan/recur Skip to content Navigation Menu Toggle navigation Sign in * Product + GitHub Copilot Write better code with AI + Security Find and fix vulnerabilities + Actions Automate any workflow + Codespaces Instant dev environments + Issues Plan and track work + Code Review Manage code changes + Discussions Collaborate outside of code + Code Search Find more, search less Explore + All features + Documentation + GitHub Skills + Blog * Solutions By company size + Enterprises + Small and medium teams + Startups By use case + DevSecOps + DevOps + CI/CD + View all use cases By industry + Healthcare + Financial services + Manufacturing + Government + View all industries View all solutions * Resources Topics + AI + DevOps + Security + Software Development + View all Explore + Learning Pathways + White papers, Ebooks, Webinars + Customer Stories + Partners * Open Source + GitHub Sponsors Fund open source developers + The ReadME Project GitHub community articles Repositories + Topics + Trending + Collections * Enterprise + Enterprise platform AI-powered developer platform Available add-ons + Advanced Security Enterprise-grade security features + GitHub Copilot Enterprise-grade AI features + Premium Support Enterprise-grade 24/7 support * Pricing Search or jump to... Search code, repositories, users, issues, pull requests... Search [ ] Clear Search syntax tips Provide feedback We read every piece of feedback, and take your input very seriously. [ ] [ ] Include my email address so I can be contacted Cancel Submit feedback Saved searches Use saved searches to filter your results more quickly Name [ ] Query [ ] To see all available qualifiers, see our documentation. Cancel Create saved search Sign in Sign up Reseting focus You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert {{ message }} dbohdan / recur Public * Notifications You must be signed in to change notification settings * Fork 0 * Star 80 Retry a command with exponential backoff and jitter (+ Starlark expressions) License MIT license 80 stars 0 forks Branches Tags Activity Star Notifications You must be signed in to change notification settings * Code * Issues 1 * Pull requests 0 * Actions * Projects 0 * Security * Insights Additional navigation options * Code * Issues * Pull requests * Actions * Projects * Security * Insights dbohdan/recur master BranchesTags [ ] Go to file Code Folders and files Name Name Last commit Last commit message date Latest commit History 151 Commits .github/workflows .github/workflows script script test test .gitattributes .gitattributes .gitignore .gitignore LICENSE LICENSE Makefile Makefile README.md README.md README.template.md README.template.md go.mod go.mod go.sum go.sum main.go main.go main_test.go main_test.go test.ps1 test.ps1 View all files Repository files navigation * README * MIT license recur recur is a command-line tool that runs a single command repeatedly until it succeeds or no more attempts are left. It implements optional exponential backoff with configurable jitter. It lets you write the success condition in Starlark. Requirements * Go 1.19 * POSIX Make for testing Installation Prebuilt binaries Prebuilt binaries for FreeBSD (amd64), Linux (aarch64, riscv64, x86_64), macOS (arm64, x86_64), NetBSD (amd64), OpenBSD (amd64), and Windows (amd64, x86) are attached to releases. Go Install Go, then run the following command: go install github.com/dbohdan/recur@latest Usage Usage: recur [-a ] [-b ] [-c ] [-d ] [-f] [-j ] [-m ] [-t ] [-v] [ ...] Retry a command with exponential backoff and jitter. Arguments: Command to run. [ ...] Arguments to the command. Flags: -h, --help Print this help message and exit. -V, --version Print version number and exit. -a, --attempts 10 Maximum number of attempts (negative for infinite). -b, --backoff 0 Base for exponential backoff (duration). -c, --condition 'code == 0' Success condition (Starlark expression). -d, --delay 0 Constant delay (duration). -f, --forever Infinite attempts. -j, --jitter '0,0' Additional random delay (maximum duration or 'min,max' duration). -m, --max-delay 1h Maximum allowed sum of constant delay and exponential backoff (duration). -t, --timeout -1s Timeout for each attempt (duration; negative for no timeout). -v, --verbose Increase verbosity (up to 3 times). The "duration" arguments take Go duration strings; for example, 0, 100ms, 2.5s, 0.5m, or 1h. The value of -j/--jitter must be either one duration string or two joined with a comma, like 1s,2s. Setting the delay (-d/--delay) increases the maximum delay (-m/ --max-delay) to that value when the maximum delay is shorter. Use -m/ --max-delay after -d/--delay if you want a shorter maximum delay. recur exits with the last command's exit code unless the user overrides this in the condition. When the command is not found during the last attempt, recur exits with the code 255. Conditions recur supports a limited form of scripting. You can define the success condition using an expression in Starlark, a small scripting language derived from Python. The default condition is code == 0. It means recur will stop retrying when the exit code of the command is zero. If you know Python, you can quickly start writing recur conditions in Starlark. The most significant differences between Starlark and Python for this purpose are: * Starlark has no is. You must write code == None, not code is None. * Starlark has no sets. Write code in (1, 2, 3) or code in [1, 2, 3] rather than code in {1, 2, 3}. You can use the following variables in the condition expression: * attempt: int -- the number of the current attempt, starting at one. Combine with --forever to use the condition instead of the built-in attempt counter. * code: int | None -- the exit code of the last command. code is None when the command was not found. * command_found: bool -- whether the last command was found. * max_attempts: int -- the value of the option --attempts. --forever sets it to -1. * time: float -- the time the most recent attempt took, in seconds. * total_time: float -- the time between the start of the first attempt and the end of the most recent, again in seconds. recur defines one custom function: * exit(code: int | None) -> None -- exit with the exit code. If code is None, exit with the exit code for a missing command (255). This function allows you to override the default behavior of returning the last command's exit code. For example, you can make recur exit with success when the command fails. recur --condition 'code != 0 and exit(0)' sh -c 'exit 1' # or recur --condition 'False if code == 0 else exit(0)' sh -c 'exit 1' In the following example we stop early and do not retry when the command's exit code indicates incorrect usage or a problem with the installation. recur --condition 'code == 0 or (code in (1, 2, 3, 4) and exit(code))' curl "$url" License MIT. Alternatives recur was inspired by retry-cli. I wanted something like retry-cli but without the Node.js dependency. There are other similar tools: * eb. Written in Rust. cargo install eb. * retry (joshdk). Written in Go. go install github.com/joshdk/ retry@master. * retry (kadwanev). Written in Bash. * retry (minfrin). Written in C. Packaged for Debian and Ubuntu. sudo apt install retry. * retry (timofurrer). Written in Rust. cargo install retry-cmd. * retry-cli. Written in JavaScript for Node.js. npx retry-cli. * SysBox includes the command splay. Written in Go. go install github.com/skx/sysbox@latest. About Retry a command with exponential backoff and jitter (+ Starlark expressions) Topics go golang retry starlark Resources Readme License MIT license Activity Stars 80 stars Watchers 2 watching Forks 0 forks Report repository Releases 6 v1.0.0 Latest Nov 18, 2024 + 5 releases Packages 0 No packages published Languages * Go 95.8% * PowerShell 2.2% * Makefile 2.0% Footer (c) 2024 GitHub, Inc. Footer navigation * Terms * Privacy * Security * Status * Docs * Contact * Manage cookies * Do not share my personal information You can't perform that action at this time.