def main(): from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument("-a", "--attempts", type=int, default=5, help="How many times to retry.") parser.add_argument("-s", "--sleeptime", type=int, default=60, help="How long to sleep between attempts. Sleeptime doubles after each attempt.") parser.add_argument("-m", "--max-sleeptime", type=int, default=5*60, help="Maximum length of time to sleep between attempts (limits backoff length).") parser.add_argument("-v", "--verbose", action="store_true", default=False) parser.add_argument("cmd", nargs="+", help="Command to run. Eg: wget http://blah") args = parser.parse_args() if args.verbose: logging.basicConfig(level=logging.INFO) logging.getLogger("retry").setLevel(logging.INFO) else: logging.basicConfig(level=logging.ERROR) logging.getLogger("retry").setLevel(logging.ERROR) try: with retrying(check_call, attempts=args.attempts, sleeptime=args.sleeptime, max_sleeptime=args.max_sleeptime, retry_exceptions=(CalledProcessError,)) as r_check_call: r_check_call(args.cmd) except KeyboardInterrupt: sys.exit(-1) except Exception as e: log.error("Unable to run command after %d attempts" % args.attempts, exc_info=True) rc = getattr(e, "returncode", -2) sys.exit(rc)
def cleanOutgoingRevs(reponame, remote, username, sshKey): outgoingRevs = retrying(out, attempts=RETRY_ATTEMPTS, kwargs=dict(src=reponame, remote=remote, ssh_username=username, ssh_key=sshKey)) for r in reversed(outgoingRevs): run_cmd(['hg', '--config', 'extensions.mq=', 'strip', '-n', r[REVISION]], cwd=reponame)
def test_retrying_call_retry(self): """Make sure to distribute retry and function args/kwargs properly""" def wrapped(*args, **kwargs): pass with mock.patch("redo.retry") as mocked_retry: with retrying(wrapped, 1, x="y") as w: w("a", b=1, c="a") mocked_retry.assert_called_once_with( wrapped, 1, x='y', args=('a',), kwargs={'c': 'a', 'b': 1})
def send_mail(self, *args, **kwargs): retry_options = { "retry_exceptions": (SMTPConnectError, SMTPServerDisconnected), # The default in redo is 60 seconds. Let's tone that down. "sleeptime": 3, "attempts": 10, } parent_method = super(KumaAccountAdapter, self).send_mail with retrying(parent_method, **retry_options) as method: return method(*args, **kwargs)
def main(argv): from argparse import ArgumentParser, REMAINDER parser = ArgumentParser() parser.add_argument("-a", "--attempts", type=int, default=5, help="How many times to retry.") parser.add_argument( "-s", "--sleeptime", type=int, default=60, help= "How long to sleep between attempts. Sleeptime doubles after each attempt." ) parser.add_argument( "-m", "--max-sleeptime", type=int, default=5 * 60, help= "Maximum length of time to sleep between attempts (limits backoff length)." ) parser.add_argument("-v", "--verbose", action="store_true", default=False) parser.add_argument("cmd", nargs=REMAINDER, help="Command to run. Eg: wget http://blah") args = parser.parse_args(argv[1:]) if args.verbose: logging.basicConfig(level=logging.INFO) logging.getLogger("retry").setLevel(logging.INFO) else: logging.basicConfig(level=logging.ERROR) logging.getLogger("retry").setLevel(logging.ERROR) try: with retrying( check_call, attempts=args.attempts, sleeptime=args.sleeptime, max_sleeptime=args.max_sleeptime, retry_exceptions=(CalledProcessError, ), ) as r_check_call: r_check_call(args.cmd) except KeyboardInterrupt: sys.exit(-1) except Exception as e: log.error("Unable to run command after %d attempts" % args.attempts, exc_info=True) rc = getattr(e, "returncode", -2) sys.exit(rc)
def test_retrying_id(self): """Make sure that the context manager doesn't change the original callable""" def wrapped(): pass before = id(wrapped) with retrying(wrapped) as w: within = id(w) after = id(wrapped) self.assertEqual(before, after) self.assertNotEqual(before, within)
def DoSCPFile(file, remote_path, user, host, port=None, ssh_key=None): """Upload file to user@host:remote_path using scp. Optionally use port and ssh_key, if provided.""" cmdline = ["scp"] AppendOptionalArgsToSSHCommandline(cmdline, port, ssh_key) cmdline.extend([WindowsPathToMsysPath(file), "%s@%s:%s" % (user, host, remote_path)]) with redo.retrying(check_call, sleeptime=10) as f: f(cmdline) return raise Exception("Command %s returned non-zero exit code" % cmdline)
def download_url(url, retry_options=None): retry_options = retry_options or { "retry_exceptions": (requests.exceptions.Timeout, ), "sleeptime": 2, "attempts": 5, } with retrying(requests.get, **retry_options) as retrying_get: response = retrying_get(url, allow_redirects=False) response.raise_for_status() return response
def DoSSHCommand(command, user, host, port=None, ssh_key=None): """Execute command on user@host using ssh. Optionally use port and ssh_key, if provided.""" cmdline = ["ssh"] AppendOptionalArgsToSSHCommandline(cmdline, port, ssh_key) cmdline.extend(["%s@%s" % (user, host), command]) with redo.retrying(check_output, sleeptime=10) as f: output = f(cmdline, stderr=STDOUT).strip() return output raise Exception("Command %s returned non-zero exit code" % cmdline)
def send(self, *args, retry_options=None, **kwargs): # See https://github.com/mozilla-releng/redo # for a list of the default options to the redo.retry function # which the redo.retrying context manager wraps. retry_options = retry_options or { "retry_exceptions": (SMTPServerDisconnected, ), # The default in redo is 60 seconds. Let's tone that down. "sleeptime": 3, } parent_method = super(EmailMultiAlternativesRetrying, self).send with retrying(parent_method, **retry_options) as method: return method(*args, **kwargs)
def _find(params, total_only=False, make_suggestions=False, min_suggestion_score=0.8): search_query = Search(index=settings.SEARCH_INDEX_NAME, ) if make_suggestions: # XXX research if it it's better to use phrase suggesters and if # that works # https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters.html#phrase-suggester search_query = search_query.suggest("title_suggestions", params["query"], term={"field": "title"}) search_query = search_query.suggest("body_suggestions", params["query"], term={"field": "body"}) sub_queries = [] sub_queries.append( Q("match", title={ "query": params["query"], "boost": 2.0 })) sub_queries.append( Q("match", body={ "query": params["query"], "boost": 1.0 })) if " " in params["query"]: sub_queries.append( Q("match_phrase", title={ "query": params["query"], "boost": 10.0 })) sub_queries.append( Q("match_phrase", body={ "query": params["query"], "boost": 5.0 })) sub_query = query.Bool(should=sub_queries) if params["locales"]: search_query = search_query.filter("terms", locale=params["locales"]) if params["archive"] == "exclude": search_query = search_query.filter("term", archived=False) elif params["archive"] == "only": search_query = search_query.filter("term", archived=True) if params["slug_prefixes"]: sub_queries = [Q("prefix", slug=x) for x in params["slug_prefixes"]] search_query = search_query.query(query.Bool(should=sub_queries)) search_query = search_query.highlight_options( pre_tags=["<mark>"], post_tags=["</mark>"], number_of_fragments=3, fragment_size=120, encoder="html", ) search_query = search_query.highlight("title", "body") if params["sort"] == "relevance": search_query = search_query.sort("_score", "-popularity") search_query = search_query.query(sub_query) elif params["sort"] == "popularity": search_query = search_query.sort("-popularity", "_score") search_query = search_query.query(sub_query) else: popularity_factor = 10.0 boost_mode = "sum" score_mode = "max" search_query = search_query.query( "function_score", query=sub_query, functions=[ query.SF( "field_value_factor", field="popularity", factor=popularity_factor, missing=0.0, ) ], boost_mode=boost_mode, score_mode=score_mode, ) search_query = search_query.source(excludes=["body"]) search_query = search_query[params["size"] * (params["page"] - 1):params["size"] * params["page"]] retry_options = { "retry_exceptions": ( # This is the standard operational exception. exceptions.ConnectionError, # This can happen if the search happened right as the index had # just been deleted due to a fresh re-indexing happening in Yari. exceptions.NotFoundError, # This can happen when the index simply isn't ready yet. exceptions.TransportError, ), # The default in redo is 60 seconds. Let's tone that down. "sleeptime": settings.ES_RETRY_SLEEPTIME, "attempts": settings.ES_RETRY_ATTEMPTS, "jitter": settings.ES_RETRY_JITTER, } with retrying(search_query.execute, **retry_options) as retrying_function: response = retrying_function() if total_only: return response.hits.total metadata = { "took_ms": response.took, "total": { # The `response.hits.total` is a `elasticsearch_dsl.utils.AttrDict` # instance. Pluck only the exact data needed. "value": response.hits.total.value, "relation": response.hits.total.relation, }, "size": params["size"], "page": params["page"], } documents = [] for hit in response: try: body_highlight = list(hit.meta.highlight.body) except AttributeError: body_highlight = [] try: title_highlight = list(hit.meta.highlight.title) except AttributeError: title_highlight = [] d = { "mdn_url": hit.meta.id, "score": hit.meta.score, "title": hit.title, "locale": hit.locale, "slug": hit.slug, "popularity": hit.popularity, "archived": hit.archived, "summary": hit.summary, "highlight": { "body": body_highlight, "title": title_highlight, }, } documents.append(d) try: suggest = getattr(response, "suggest") except AttributeError: suggest = None suggestions = [] if suggest: suggestion_strings = _unpack_suggestions( params["query"], response.suggest, ("body_suggestions", "title_suggestions"), ) for score, string in suggestion_strings: if score > min_suggestion_score or 1: # Sure, this is different way to spell, but what will it yield # if you actually search it? total = _find(dict(params, query=string), total_only=True) if total["value"] > 0: suggestions.append({ "text": string, "total": { # This 'total' is an `AttrDict` instance. "value": total.value, "relation": total.relation, }, }) # Since they're sorted by score, it's usually never useful # to suggestion more than exactly 1 good suggestion. break return { "documents": documents, "metadata": metadata, "suggestions": suggestions, }