retry.py (1556B)
1 #!/usr/bin/env python3 2 import argparse 3 import subprocess 4 import time 5 import sys 6 7 8 def get_args() -> argparse.ArgumentParser: 9 parser = argparse.ArgumentParser() 10 parser.add_argument("--delay", type=float, default=3, 11 help="Initial delay before retry, in seconds") 12 parser.add_argument("--count", type=int, default=5, help="Total number of tries") 13 parser.add_argument("--factor", type=float, default=2, 14 help="Exponential backoff factor") 15 parser.add_argument("cmd", nargs=argparse.REMAINDER) 16 return parser 17 18 19 def log(value: str) -> None: 20 print(value) 21 sys.stdout.flush() 22 23 24 def main() -> None: 25 args = get_args().parse_args() 26 27 if not args.cmd: 28 log("No command supplied") 29 sys.exit(1) 30 31 retcode = None 32 33 for n in range(args.count): 34 try: 35 log("Running %s [try %d/%d]" % (" ".join(args.cmd), (n+1), args.count)) 36 subprocess.check_call(args.cmd) 37 except subprocess.CalledProcessError as e: 38 retcode = e.returncode 39 else: 40 log("Command succeeded") 41 retcode = 0 42 break 43 44 if args.factor == 0: 45 wait_time = (n+1) * args.delay 46 else: 47 wait_time = args.factor**n * args.delay 48 if n < args.count - 1: 49 log("Command failed, waiting %s seconds to retry" % wait_time) 50 time.sleep(wait_time) 51 else: 52 log("Command failed, out of retries") 53 54 sys.exit(retcode) 55 56 57 if __name__ == "__main__": 58 main()