Chromium Code Reviews| Index: tools/push-to-trunk/common_includes.py |
| diff --git a/tools/push-to-trunk/common_includes.py b/tools/push-to-trunk/common_includes.py |
| index 4f77c6b4ac728b202db79cad5ff0e06664b07b70..668f95e0554f494363749858eb6c6ee7afba0455 100644 |
| --- a/tools/push-to-trunk/common_includes.py |
| +++ b/tools/push-to-trunk/common_includes.py |
| @@ -31,6 +31,7 @@ import re |
| import subprocess |
| import sys |
| import textwrap |
| +import time |
| import urllib2 |
| PERSISTFILE_BASENAME = "PERSISTFILE_BASENAME" |
| @@ -173,6 +174,7 @@ def MakeChangeLogBugReference(body): |
| # Some commands don't like the pipe, e.g. calling vi from within the script or |
| # from subscripts like git cl upload. |
| def Command(cmd, args="", prefix="", pipe=True): |
| + # TODO(machenbach): Use timeout. |
| cmd_line = "%s %s %s" % (prefix, cmd, args) |
| print "Command: %s" % cmd_line |
| try: |
| @@ -200,6 +202,9 @@ class SideEffectHandler(object): |
| finally: |
| url_fh.close() |
| + def Sleep(seconds): |
| + time.sleep(seconds) |
| + |
| DEFAULT_SIDE_EFFECT_HANDLER = SideEffectHandler() |
| @@ -231,6 +236,36 @@ class Step(object): |
| def RunStep(self): |
| raise NotImplementedError |
| + def Retry(self, cb, retry_on=None, wait_plan=None): |
| + """ Retry a function. |
| + Params: |
| + cb: The function to retry. |
| + retry_on: A callback that takes the result of the function and returns True |
|
Jakob Kummerow
2013/11/28 13:47:27
nit: 80col
Michael Achenbach
2013/11/28 14:28:17
Done.
|
| + if the function should be retried. A function throwing an |
| + exception is always retried. |
| + wait_plan: A list of waiting delays between retries in seconds. The maximum |
|
Jakob Kummerow
2013/11/28 13:47:27
nit: 80col
Michael Achenbach
2013/11/28 14:28:17
Done.
|
| + number of retries is len(wait_plan). |
| + """ |
| + retry_on = retry_on or (lambda x: False) |
| + wait_plan = list(wait_plan or []) |
|
Jakob Kummerow
2013/11/28 13:47:27
I don't think the explicit list() conversion is ne
Michael Achenbach
2013/11/28 14:28:17
I'd rather keep it, since the method has side effe
|
| + # Sentinel for the first try. |
|
Jakob Kummerow
2013/11/28 13:47:27
s/first/last/! This is seriously misleading.
Here
Michael Achenbach
2013/11/28 14:28:17
I take it :) Just added an initialization of got_e
|
| + wait_plan.append(0) |
| + wait_plan.reverse() |
| + while wait_plan: |
| + got_exception = False |
| + try: |
| + result = cb() |
| + except Exception: |
| + got_exception = True |
| + if got_exception or retry_on(result): |
| + wait_time = wait_plan.pop() |
| + print "Waiting for %f seconds." % wait_time |
| + self._side_effect_handler.Sleep(wait_time) |
| + print "Retrying..." |
| + else: |
| + return result |
| + raise Exception("Retried too often. Giving up.") |
| + |
| def ReadLine(self, default=None): |
| # Don't prompt in forced mode. |
| if self._options and self._options.f and default is not None: |
| @@ -239,15 +274,18 @@ class Step(object): |
| else: |
| return self._side_effect_handler.ReadLine() |
| - def Git(self, args="", prefix="", pipe=True): |
| - return self._side_effect_handler.Command("git", args, prefix, pipe) |
| + def Git(self, args="", prefix="", pipe=True, retry_on=None): |
| + cmd = lambda: self._side_effect_handler.Command("git", args, prefix, pipe) |
| + return self.Retry(cmd, retry_on, [5, 30]) |
| def Editor(self, args): |
| return self._side_effect_handler.Command(os.environ["EDITOR"], args, |
| pipe=False) |
| - def ReadURL(self, url): |
| - return self._side_effect_handler.ReadURL(url) |
| + def ReadURL(self, url, retry_on=None, wait_plan=None): |
| + wait_plan = wait_plan or [3, 10, 30] |
|
Jakob Kummerow
2013/11/28 13:47:27
I'd give the server much more time. Maybe [3, 60,
Michael Achenbach
2013/11/28 14:28:17
Done.
|
| + cmd = lambda: self._side_effect_handler.ReadURL(url) |
| + return self.Retry(cmd, retry_on, wait_plan) |
| def Die(self, msg=""): |
| if msg != "": |