Skip to content

Commit ddc8dde

Browse files
committed
[SAC-27535] Updated http.py to improve rate limit handling
1 parent e50cc1d commit ddc8dde

File tree

1 file changed

+12
-13
lines changed

1 file changed

+12
-13
lines changed

tap_frontapp/http.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
11
import json
22
import time
3-
43
import requests
54
import backoff
65
import singer
76
from singer import metrics
87

98
LOGGER = singer.get_logger()
109

11-
1210
class RateLimitException(Exception):
1311
pass
1412

15-
1613
class MetricsRateLimitException(Exception):
1714
pass
1815

19-
2016
class Client(object):
2117
BASE_URL = 'https://api2.frontapp.com'
2218

2319
def __init__(self, config):
2420
self.token = 'Bearer ' + config.get('token')
2521
self.session = requests.Session()
26-
2722
self.calls_remaining = None
2823
self.limit_reset = None
2924

3025
def url(self, path):
3126
return self.BASE_URL + path
3227

28+
# Log backoff retries
29+
def log_backoff(details):
30+
LOGGER.warning(f"[Backoff] Retrying {details['target'].__name__} in {details['wait']}s due to {details['exception']}")
31+
32+
# Retry strategy: Max 5 retries or 60 seconds total
3333
@backoff.on_exception(backoff.expo,
3434
RateLimitException,
35-
max_tries=10,
36-
factor=2)
35+
max_tries=5,
36+
max_time=60,
37+
on_backoff=log_backoff)
3738
def request(self, method, url, **kwargs):
3839
if self.calls_remaining is not None and self.calls_remaining == 0:
3940
wait = self.limit_reset - int(time.monotonic())
@@ -53,13 +54,12 @@ def request(self, method, url, **kwargs):
5354
with metrics.http_request_timer(endpoint) as timer:
5455
response = requests.request(method, url, **kwargs)
5556
timer.tags[metrics.Tag.http_status_code] = response.status_code
56-
57-
5857
else:
5958
response = requests.request(method, url, **kwargs)
6059

61-
self.calls_remaining = int(response.headers['X-Ratelimit-Remaining'])
62-
self.limit_reset = int(float(response.headers['X-Ratelimit-Reset']))
60+
#Handled missing headers to avoid KeyError
61+
self.calls_remaining = int(response.headers.get('X-Ratelimit-Remaining', 1))
62+
self.limit_reset = int(float(response.headers.get('X-Ratelimit-Reset', time.monotonic() + 1)))
6363

6464
if response.status_code in [429, 503]:
6565
raise RateLimitException(response.text)
@@ -83,10 +83,9 @@ def create_report(self, path, data, **kwargs):
8383
response = self.request('post', url, **kwargs)
8484
if response.json().get('_links', {}).get('self'):
8585
return response.json()['_links']['self']
86-
8786
return {}
8887

8988
def list_metrics(self, path, **kwargs):
9089
url = self.url(path)
9190
response = self.request('get', url, **kwargs)
92-
return response.json().get('_results', [])
91+
return response.json().get('_results', [])

0 commit comments

Comments
 (0)