strizhechenko/shell-retry

View on GitHub
shell_retry/__init__.py

Summary

Maintainability
A
0 mins
Test Coverage
# coding=utf-8

import argparse
import logging
import time
from subprocess import Popen


def setup_logging(args):
    log_format = "%(asctime)s %(levelname)s: %(message)s"
    level = logging.INFO if args.verbose else logging.WARNING
    logging.basicConfig(format=log_format, level=level)


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('--backoff', help='backoff factor (sleep(--interval *= --backoff)', type=float, default=1)
    parser.add_argument('--retry-count', type=int, help='How many time re-run cmd if it fails', default=1)
    parser.add_argument('--interval', help='Initial interval between retries', type=float, default=1)
    parser.add_argument('--interval-max', help='upper limit for interval', type=float)
    parser.add_argument('--interval-min', help='lower limit for interval', type=float)
    parser.add_argument('--verbose', help='Be verbose, write how many retries left and how long will we wait',
                        action='store_true', default=False)
    parser.add_argument("cmd", nargs='+', type=str, action='store')
    return parser.parse_args()


def next_interval(args):
    interval = args.interval
    interval *= args.backoff
    if args.interval_max is not None:
        interval = min(interval, args.interval_max)
    if args.interval_min is not None:
        interval = max(interval, args.interval_min)
    return interval


def __run(args, retry):
    logging.info("run {0}".format(args.cmd))
    process = Popen(args.cmd)
    process.communicate()
    if process.returncode == 0:
        exit(0)
    logging.info("command returned {0}".format(process.returncode))
    try:
        process.kill()
    except OSError:
        pass
    if retry <= 0:
        exit(process.returncode)
    logging.info('waiting {0:f} seconds, {1} retries left'.format(args.interval, retry))
    time.sleep(args.interval)
    args.interval = next_interval(args)


def run(args):
    logging.info(args)
    for retry in range(args.retry_count, -1, -1):
        __run(args, retry)
    exit(1)


def main():
    args = parse_args()
    setup_logging(args)
    run(args)


if __name__ == '__main__':
    main()