Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Logic to Handle if Key Encounters GitHub API Rate Limit #268

Merged
merged 4 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scripts/metricsLib/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from enum import Enum

TIMEOUT_IN_SECONDS = 120
REQUEST_RETRIES = 5
BASE_PATH = os.path.dirname(os.path.abspath(__file__))
# Folder Names to send over our projects tracked data
PATH_TO_METRICS_DATA = (Path(__file__).parent /
Expand Down
66 changes: 47 additions & 19 deletions scripts/metricsLib/metrics_data_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
import json
from json.decoder import JSONDecodeError
import datetime
from time import sleep, mktime, gmtime, time, localtime
from functools import reduce
import operator
import requests
from metricsLib.constants import TIMEOUT_IN_SECONDS, GH_GQL_ENDPOINT
from metricsLib.constants import TIMEOUT_IN_SECONDS, GH_GQL_ENDPOINT, REQUEST_RETRIES

# Simple metric that can be represented by a count or value.

Expand Down Expand Up @@ -48,7 +49,7 @@
before returning it.
"""

def __init__(self, name, needed_params, endpoint_url, return_values, token=None, method='GET'):

Check warning on line 52 in scripts/metricsLib/metrics_data_structures.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 R0913: Too many arguments (7/5) (too-many-arguments) Raw Output: scripts/metricsLib/metrics_data_structures.py:52:4: R0913: Too many arguments (7/5) (too-many-arguments)

Check warning on line 52 in scripts/metricsLib/metrics_data_structures.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 R0917: Too many positional arguments (7/5) (too-many-positional-arguments) Raw Output: scripts/metricsLib/metrics_data_structures.py:52:4: R0917: Too many positional arguments (7/5) (too-many-positional-arguments)
self.name = name
self.return_values = return_values
self.url = endpoint_url
Expand All @@ -75,25 +76,52 @@
endpoint_to_hit = self.url.format(**params)
request_params = None

if self.headers:
_args_ = (self.method, endpoint_to_hit)
_kwargs_ = {
"params": request_params,
"headers": self.headers,
"timeout": TIMEOUT_IN_SECONDS
}
response = requests.request(*_args_, **_kwargs_)
else:
response = requests.request(
self.method, endpoint_to_hit, params=request_params, timeout=TIMEOUT_IN_SECONDS)

try:
if response.status_code == 200:
response_json = json.loads(response.text)
attempts = 0

while attempts < REQUEST_RETRIES:
if self.headers:
_args_ = (self.method, endpoint_to_hit)
_kwargs_ = {
"params": request_params,
"headers": self.headers,
"timeout": TIMEOUT_IN_SECONDS
}
response = requests.request(*_args_, **_kwargs_)
else:
raise ConnectionError(f"Non valid status code {response.status_code}!")
except JSONDecodeError:
response_json = {}
response = requests.request(
self.method, endpoint_to_hit, params=request_params, timeout=TIMEOUT_IN_SECONDS)

try:
if response.status_code == 200:
response_json = json.loads(response.text)
break
elif response.status_code in (403,429):
#rate limit was triggered.
wait_until = int(response.headers.get("x-ratelimit-reset"))
wait_in_seconds = int(
mktime(gmtime(wait_until)) -
mktime(gmtime(time()))
)
wait_until_time = localtime(wait_until)

print(f"Ran into rate limit sleeping for {self.name}!")
print(
f"sleeping until {wait_until_time.tm_hour}:{wait_until_time.tm_min} ({wait_in_seconds} seconds)"
)
sleep(wait_in_seconds)

response_json = {}
attempts += 1

if attempts >= REQUEST_RETRIES:
raise ConnectionError(
f"Rate limit was reached and couldn't be rectified after {attempts} tries"
)
else:
raise ConnectionError(f"Non valid status code {response.status_code}!")
except JSONDecodeError:
response_json = {}
attempts += 1

return response_json

Expand Down Expand Up @@ -143,7 +171,7 @@
Fetch data and save it in desired path and format
"""

def __init__(self, name, needed_params, url, fmt='png', token=None):

Check warning on line 174 in scripts/metricsLib/metrics_data_structures.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 R0913: Too many arguments (6/5) (too-many-arguments) Raw Output: scripts/metricsLib/metrics_data_structures.py:174:4: R0913: Too many arguments (6/5) (too-many-arguments)

Check warning on line 174 in scripts/metricsLib/metrics_data_structures.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 R0917: Too many positional arguments (6/5) (too-many-positional-arguments) Raw Output: scripts/metricsLib/metrics_data_structures.py:174:4: R0917: Too many positional arguments (6/5) (too-many-positional-arguments)
super().__init__(name, needed_params, url, {}, token=token)
self.format = fmt

Expand Down Expand Up @@ -224,7 +252,7 @@
"""
# Return value is a dict of lists of strings that match to the keys of the dict.

def __init__(self, name, needed_params, query, return_vals, token=None, url=GH_GQL_ENDPOINT):

Check warning on line 255 in scripts/metricsLib/metrics_data_structures.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 R0913: Too many arguments (7/5) (too-many-arguments) Raw Output: scripts/metricsLib/metrics_data_structures.py:255:4: R0913: Too many arguments (7/5) (too-many-arguments)

Check warning on line 255 in scripts/metricsLib/metrics_data_structures.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 R0917: Too many positional arguments (7/5) (too-many-positional-arguments) Raw Output: scripts/metricsLib/metrics_data_structures.py:255:4: R0917: Too many positional arguments (7/5) (too-many-positional-arguments)
super().__init__(name, needed_params, url, return_vals, token=token)
self.query = query

Expand Down Expand Up @@ -263,10 +291,10 @@

if "data" not in response_json.keys():
if "message" not in response_json.keys():
raise requests.exceptions.InvalidJSONError(

Check warning on line 294 in scripts/metricsLib/metrics_data_structures.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 E1101: Module 'requests.exceptions' has no 'InvalidJSONError' member (no-member) Raw Output: scripts/metricsLib/metrics_data_structures.py:294:22: E1101: Module 'requests.exceptions' has no 'InvalidJSONError' member (no-member)
response_json['errors'][0]['message'])

raise requests.exceptions.InvalidJSONError(

Check warning on line 297 in scripts/metricsLib/metrics_data_structures.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 E1101: Module 'requests.exceptions' has no 'InvalidJSONError' member (no-member) Raw Output: scripts/metricsLib/metrics_data_structures.py:297:18: E1101: Module 'requests.exceptions' has no 'InvalidJSONError' member (no-member)
response_json['message'])

# print(f"Response_JSON: {response_json}")
Expand Down Expand Up @@ -298,7 +326,7 @@
before returning it.
"""

def __init__(self, name, needed_params, endpoint_url, return_val, token=None, method='GET'):

Check warning on line 329 in scripts/metricsLib/metrics_data_structures.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 R0913: Too many arguments (7/5) (too-many-arguments) Raw Output: scripts/metricsLib/metrics_data_structures.py:329:4: R0913: Too many arguments (7/5) (too-many-arguments)

Check warning on line 329 in scripts/metricsLib/metrics_data_structures.py

View workflow job for this annotation

GitHub Actions / runner / pylint

[pylint] reported by reviewdog 🐶 R0917: Too many positional arguments (7/5) (too-many-positional-arguments) Raw Output: scripts/metricsLib/metrics_data_structures.py:329:4: R0917: Too many positional arguments (7/5) (too-many-positional-arguments)
super().__init__(name, needed_params, endpoint_url,
return_val, token=token, method=method)

Expand Down
Loading