|
34 | 34 | from .version import __version__ as umapi_version |
35 | 35 |
|
36 | 36 |
|
| 37 | +class APIResult: |
| 38 | + success_codes = [200, 201, 204] |
| 39 | + timeout_codes = [429, 502, 503, 504] |
| 40 | + client_error = lambda self, x: 201 <= x < 200 |
| 41 | + request_error = lambda self, x: 400 <= x < 500 |
| 42 | + |
| 43 | + def __init__(self, result=None, success=False, timeout=None): |
| 44 | + self.result = result |
| 45 | + self.success = success |
| 46 | + self.timeout = timeout |
| 47 | + |
| 48 | + def check_result(self): |
| 49 | + if self.result.status_code in self.success_codes: |
| 50 | + self.success = True |
| 51 | + return self |
| 52 | + if self.result.status_code in self.timeout_codes: |
| 53 | + self.success = False |
| 54 | + self.timeout = self.get_timeout() |
| 55 | + return self |
| 56 | + print("STATUS", self.result.status_code) |
| 57 | + if self.client_error(self.result.status_code): |
| 58 | + raise ClientError("Unexpected HTTP Status {:d}: {}".format(self.result.status_code, self.result.text), self.result) |
| 59 | + if self.request_error(self.result.status_code): |
| 60 | + raise RequestError(self.result) |
| 61 | + raise ServerError(self.result) |
| 62 | + |
| 63 | + def get_timeout(self): |
| 64 | + if "Retry-After" in self.result.headers: |
| 65 | + advice = self.result.headers["Retry-After"] |
| 66 | + advised_time = parsedate_tz(advice) |
| 67 | + if advised_time is not None: |
| 68 | + # header contains date |
| 69 | + return int(mktime_tz(advised_time) - time()) |
| 70 | + else: |
| 71 | + # header contains delta seconds |
| 72 | + return int(advice) |
| 73 | + return 0 |
| 74 | + |
37 | 75 | class Connection: |
38 | 76 | """ |
39 | 77 | An org-specific, authorized connection to the UMAPI service. Each method |
@@ -439,38 +477,27 @@ def call(): |
439 | 477 | start_time = time() |
440 | 478 | result = None |
441 | 479 | for num_attempts in range(1, self.retry_max_attempts + 1): |
| 480 | + checked_result = None |
442 | 481 | try: |
443 | 482 | result = call() |
444 | | - if result.status_code in [200,201,204]: |
445 | | - return result |
446 | | - elif result.status_code in [429, 502, 503, 504]: |
447 | | - if self.logger: self.logger.warning("UMAPI timeout...service unavailable (code %d on try %d)", |
448 | | - result.status_code, num_attempts) |
449 | | - retry_wait = 0 |
450 | | - if "Retry-After" in result.headers: |
451 | | - advice = result.headers["Retry-After"] |
452 | | - advised_time = parsedate_tz(advice) |
453 | | - if advised_time is not None: |
454 | | - # header contains date |
455 | | - retry_wait = int(mktime_tz(advised_time) - time()) |
456 | | - else: |
457 | | - # header contains delta seconds |
458 | | - retry_wait = int(advice) |
459 | | - if retry_wait <= 0: |
460 | | - # use exponential back-off with random delay |
461 | | - delay = randint(0, self.retry_random_delay) |
462 | | - retry_wait = (int(pow(2, num_attempts - 1)) * self.retry_first_delay) + delay |
463 | | - elif 201 <= result.status_code < 400: |
464 | | - raise ClientError("Unexpected HTTP Status {:d}: {}".format(result.status_code, result.text), result) |
465 | | - elif 400 <= result.status_code < 500: |
466 | | - raise RequestError(result) |
467 | | - else: |
468 | | - raise ServerError(result) |
| 483 | + checked_result = APIResult(result).check_result() |
469 | 484 | except requests.Timeout: |
470 | 485 | if self.logger: self.logger.warning("UMAPI connection timeout...(%d seconds on try %d)", |
471 | 486 | self.timeout, num_attempts) |
472 | | - retry_wait = 0 |
473 | | - result = None |
| 487 | + checked_result = APIResult(success=False, timeout=0) |
| 488 | + |
| 489 | + if checked_result.success: |
| 490 | + return result |
| 491 | + |
| 492 | + if self.logger: self.logger.warning("UMAPI timeout...service unavailable (code %d on try %d)", |
| 493 | + result.status_code, num_attempts) |
| 494 | + |
| 495 | + retry_wait = checked_result.timeout |
| 496 | + if retry_wait <= 0: |
| 497 | + # use exponential back-off with random delay |
| 498 | + delay = randint(0, self.retry_random_delay) |
| 499 | + retry_wait = (int(pow(2, num_attempts - 1)) * self.retry_first_delay) + delay |
| 500 | + |
474 | 501 | if num_attempts < self.retry_max_attempts: |
475 | 502 | if retry_wait > 0: |
476 | 503 | if self.logger: self.logger.warning("Next retry in %d seconds...", retry_wait) |
|
0 commit comments