Skip to content

Commit 5236b3e

Browse files
authored
Merge pull request #26 from williamnswanson/INF-2871.backoff-fix
(INF-2871) Fix COmanage API request back-off in scripts.
2 parents 80a0cd3 + de912b7 commit 5236b3e

File tree

1 file changed

+33
-17
lines changed

1 file changed

+33
-17
lines changed

comanage_utils.py

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import os
44
import re
5-
import sys
65
import json
6+
import time
77
import urllib.error
88
import urllib.request
99
from ldap3 import Server, Connection, ALL, ALL_ATTRIBUTES, SAFE_SYNC
@@ -26,17 +26,26 @@
2626
TEST_UNIX_CLUSTER_ID = 10
2727
TEST_LDAP_TARGET_ID = 9
2828

29-
30-
MIN_TIMEOUT = 5
31-
MAX_TIMEOUT = 625
32-
TIMEOUTMULTIPLE = 5
29+
# Value for the base of the exponential backoff
30+
TIMEOUT_BASE = 5
31+
MAX_ATTEMPTS = 5
3332

3433

3534
GET = "GET"
3635
PUT = "PUT"
3736
POST = "POST"
3837
DELETE = "DELETE"
3938

39+
#Exceptions
40+
class Error(Exception):
41+
"""Base exception class for all exceptions defined"""
42+
pass
43+
44+
45+
class URLRequestError(Error):
46+
"""Class for exceptions due to not being able to fulfill a URLRequest"""
47+
pass
48+
4049

4150
def getpw(user, passfd, passfile):
4251
if ":" in user:
@@ -81,21 +90,28 @@ def call_api2(method, target, endpoint, authstr, **kw):
8190

8291
def call_api3(method, target, data, endpoint, authstr, **kw):
8392
req = mkrequest(method, target, data, endpoint, authstr, **kw)
84-
trying = True
85-
currentTimeout = MIN_TIMEOUT
86-
while trying:
93+
req_attempts = 0
94+
current_timeout = TIMEOUT_BASE
95+
total_timeout = 0
96+
payload = None
97+
while req_attempts < MAX_ATTEMPTS:
8798
try:
88-
resp = urllib.request.urlopen(req, timeout=currentTimeout)
89-
payload = resp.read()
90-
trying = False
99+
resp = urllib.request.urlopen(req, timeout=current_timeout)
100+
# exception catching, mainly for request timeouts, "Service Temporarily Unavailable" (Rate limiting), and DNS failures.
91101
except urllib.error.URLError as exception:
92-
if currentTimeout < MAX_TIMEOUT:
93-
currentTimeout *= TIMEOUTMULTIPLE
94-
else:
95-
sys.exit(
96-
f"Exception raised after maximum number of retries and/or timeout {MAX_TIMEOUT} seconds reached. "
97-
+ f"Exception reason: {exception.reason}.\n Request: {req.full_url}"
102+
req_attempts += 1
103+
if req_attempts >= MAX_ATTEMPTS:
104+
raise URLRequestError(
105+
"Exception raised after maximum number of retries reached after total backoff of " +
106+
f"{total_timeout} seconds. Retries: {req_attempts}. "
107+
+ f"Exception reason: {exception}.\n Request: {req.full_url}"
98108
)
109+
time.sleep(current_timeout)
110+
total_timeout += current_timeout
111+
current_timeout *= TIMEOUT_BASE
112+
else:
113+
payload = resp.read()
114+
break
99115

100116
return json.loads(payload) if payload else None
101117

0 commit comments

Comments
 (0)