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
+ self .status_code = result .status_code if hasattr (result , 'status_code' ) else 'Error'
48
+
49
+ def check_result (self ):
50
+ if self .result .status_code in self .success_codes :
51
+ self .success = True
52
+ return self
53
+ if self .result .status_code in self .timeout_codes :
54
+ self .success = False
55
+ self .timeout = self .get_timeout ()
56
+ return self
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
@@ -446,38 +484,31 @@ def call():
446
484
start_time = time ()
447
485
result = None
448
486
for num_attempts in range (1 , self .retry_max_attempts + 1 ):
487
+ checked_result = None
449
488
try :
450
489
result = call ()
451
- if result .status_code in [200 ,201 ,204 ]:
452
- return result
453
- elif result .status_code in [429 , 502 , 503 , 504 ]:
454
- if self .logger : self .logger .warning ("UMAPI timeout...service unavailable (code %d on try %d)" ,
455
- result .status_code , num_attempts )
456
- retry_wait = 0
457
- if "Retry-After" in result .headers :
458
- advice = result .headers ["Retry-After" ]
459
- advised_time = parsedate_tz (advice )
460
- if advised_time is not None :
461
- # header contains date
462
- retry_wait = int (mktime_tz (advised_time ) - time ())
463
- else :
464
- # header contains delta seconds
465
- retry_wait = int (advice )
466
- if retry_wait <= 0 :
467
- # use exponential back-off with random delay
468
- delay = randint (0 , self .retry_random_delay )
469
- retry_wait = (int (pow (2 , num_attempts - 1 )) * self .retry_first_delay ) + delay
470
- elif 201 <= result .status_code < 400 :
471
- raise ClientError ("Unexpected HTTP Status {:d}: {}" .format (result .status_code , result .text ), result )
472
- elif 400 <= result .status_code < 500 :
473
- raise RequestError (result )
474
- else :
475
- raise ServerError (result )
490
+ checked_result = APIResult (result ).check_result ()
476
491
except requests .Timeout :
477
492
if self .logger : self .logger .warning ("UMAPI connection timeout...(%d seconds on try %d)" ,
478
493
self .timeout , num_attempts )
479
- retry_wait = 0
480
- result = None
494
+ checked_result = APIResult (success = False , timeout = 0 )
495
+ except requests .ConnectionError :
496
+ if self .logger : self .logger .warning ("UMAPI connection error...(%d seconds on try %d)" ,
497
+ self .timeout , num_attempts )
498
+ checked_result = APIResult (success = False , timeout = 0 )
499
+
500
+ if checked_result .success :
501
+ return result
502
+
503
+ if self .logger : self .logger .warning ("UMAPI timeout...service unavailable (code %s on try %d)" ,
504
+ checked_result .status_code , num_attempts )
505
+
506
+ retry_wait = checked_result .timeout
507
+ if retry_wait <= 0 :
508
+ # use exponential back-off with random delay
509
+ delay = randint (0 , self .retry_random_delay )
510
+ retry_wait = (int (pow (2 , num_attempts - 1 )) * self .retry_first_delay ) + delay
511
+
481
512
if num_attempts < self .retry_max_attempts :
482
513
if retry_wait > 0 :
483
514
if self .logger : self .logger .warning ("Next retry in %d seconds..." , retry_wait )
@@ -487,4 +518,4 @@ def call():
487
518
total_time = int (time () - start_time )
488
519
if self .logger : self .logger .error ("UMAPI timeout...giving up after %d attempts (%d seconds)." ,
489
520
self .retry_max_attempts , total_time )
490
- raise UnavailableError (self .retry_max_attempts , total_time , result )
521
+ raise UnavailableError (self .retry_max_attempts , total_time , checked_result . result )
0 commit comments