| OLD | NEW |
| 1 # Copyright 2013 The LUCI Authors. All rights reserved. | 1 # Copyright 2013 The LUCI Authors. All rights reserved. |
| 2 # Use of this source code is governed under the Apache License, Version 2.0 | 2 # Use of this source code is governed under the Apache License, Version 2.0 |
| 3 # that can be found in the LICENSE file. | 3 # that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import contextlib | 5 import contextlib |
| 6 import datetime |
| 6 import functools | 7 import functools |
| 8 import logging |
| 7 import os | 9 import os |
| 8 import sys | 10 import sys |
| 9 import traceback | 11 import traceback |
| 12 import time |
| 10 import urllib | 13 import urllib |
| 11 | 14 |
| 12 from cStringIO import StringIO | 15 from cStringIO import StringIO |
| 13 | 16 |
| 14 class RecipeAbort(Exception): | 17 class RecipeAbort(Exception): |
| 15 pass | 18 pass |
| 16 | 19 |
| 17 | 20 |
| 18 class ModuleInjectionError(AttributeError): | 21 class ModuleInjectionError(AttributeError): |
| 19 pass | 22 pass |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 self.lines[-1].write(s) | 186 self.lines[-1].write(s) |
| 184 break | 187 break |
| 185 self.lines[-1].write(s[:i]) | 188 self.lines[-1].write(s[:i]) |
| 186 self.lines[-1] = self.lines[-1].getvalue() | 189 self.lines[-1] = self.lines[-1].getvalue() |
| 187 self.lines.append(StringIO()) | 190 self.lines.append(StringIO()) |
| 188 s = s[i+1:] | 191 s = s[i+1:] |
| 189 | 192 |
| 190 def close(self): | 193 def close(self): |
| 191 if not isinstance(self.lines[-1], basestring): | 194 if not isinstance(self.lines[-1], basestring): |
| 192 self.lines[-1] = self.lines[-1].getvalue() | 195 self.lines[-1] = self.lines[-1].getvalue() |
| 196 |
| 197 |
| 198 class exponential_retry(object): |
| 199 """Decorator which retries the function if an exception is encountered.""" |
| 200 |
| 201 def __init__(self, retries=None, delay=None, condition=None): |
| 202 """Creates a new exponential retry decorator. |
| 203 |
| 204 Args: |
| 205 retries (int): Maximum number of retries before giving up. |
| 206 delay (datetime.timedelta): Amount of time to wait before retrying. This |
| 207 will double every retry attempt (exponential). |
| 208 condition (func): If not None, a function that will be passed the |
| 209 exception as its one argument. Retries will only happen if this |
| 210 function returns True. If None, retries will always happen. |
| 211 """ |
| 212 self.retries = retries or 5 |
| 213 self.delay = delay or datetime.timedelta(seconds=1) |
| 214 self.condition = condition or (lambda e: True) |
| 215 |
| 216 def __call__(self, f): |
| 217 @functools.wraps(f) |
| 218 def wrapper(*args, **kwargs): |
| 219 retry_delay = self.delay |
| 220 for i in xrange(self.retries): |
| 221 try: |
| 222 return f(*args, **kwargs) |
| 223 except Exception as e: |
| 224 if (i+1) >= self.retries or not self.condition(e): |
| 225 raise |
| 226 logging.exception('Exception encountered, retrying in %s', |
| 227 retry_delay) |
| 228 time.sleep(retry_delay.total_seconds()) |
| 229 retry_delay *= 2 |
| 230 return wrapper |
| OLD | NEW |