-
Notifications
You must be signed in to change notification settings - Fork 174
Closed
Labels
bugThis points to a verified bug in the codeThis points to a verified bug in the code
Description
Checklist
- I have looked into the Readme and Examples, and have not found a suitable solution or answer.
- I have looked into the API documentation and have not found a suitable solution or answer.
- I have searched the issues and have not found a suitable solution or answer.
- I have searched the Auth0 Community forums and have not found a suitable solution or answer.
- I agree to the terms within the Auth0 Code of Conduct.
Description
If you make a lot of API calls after each other, you will run into Error Code 429 of GlobalRateLimit.
Only GET implements retries, as you can see here:
Lines 139 to 178 in 8e1bf4a
def get( | |
self, | |
url: str, | |
params: dict[str, Any] | None = None, | |
headers: dict[str, str] | None = None, | |
) -> Any: | |
request_headers = self.base_headers.copy() | |
request_headers.update(headers or {}) | |
# Track the API request attempt number | |
attempt = 0 | |
# Reset the metrics tracker | |
self._metrics = {"retries": 0, "backoff": []} | |
while True: | |
# Increment attempt number | |
attempt += 1 | |
# Issue the request | |
response = requests.get( | |
url, | |
params=params, | |
headers=request_headers, | |
timeout=self.options.timeout, | |
) | |
# If the response did not have a 429 header, or the attempt number is greater than the configured retries, break | |
if response.status_code != 429 or attempt > self._retries: | |
break | |
wait = self._calculate_wait(attempt) | |
# Skip calling sleep() when running unit tests | |
if self._skip_sleep is False: | |
# sleep() functions in seconds, so convert the milliseconds formula above accordingly | |
sleep(wait / 1000) | |
# Return the final Response | |
return self._process_response(response) |
The retry implementation for POST/FILE_POST/PATCH/PUT/DELETE is missing, as you can see here:
Lines 180 to 239 in 8e1bf4a
def post( | |
self, | |
url: str, | |
data: RequestData | None = None, | |
headers: dict[str, str] | None = None, | |
) -> Any: | |
request_headers = self.base_headers.copy() | |
request_headers.update(headers or {}) | |
response = requests.post( | |
url, json=data, headers=request_headers, timeout=self.options.timeout | |
) | |
return self._process_response(response) | |
def file_post( | |
self, | |
url: str, | |
data: RequestData | None = None, | |
files: dict[str, Any] | None = None, | |
) -> Any: | |
headers = self.base_headers.copy() | |
headers.pop("Content-Type", None) | |
response = requests.post( | |
url, data=data, files=files, headers=headers, timeout=self.options.timeout | |
) | |
return self._process_response(response) | |
def patch(self, url: str, data: RequestData | None = None) -> Any: | |
headers = self.base_headers.copy() | |
response = requests.patch( | |
url, json=data, headers=headers, timeout=self.options.timeout | |
) | |
return self._process_response(response) | |
def put(self, url: str, data: RequestData | None = None) -> Any: | |
headers = self.base_headers.copy() | |
response = requests.put( | |
url, json=data, headers=headers, timeout=self.options.timeout | |
) | |
return self._process_response(response) | |
def delete( | |
self, | |
url: str, | |
params: dict[str, Any] | None = None, | |
data: RequestData | None = None, | |
) -> Any: | |
headers = self.base_headers.copy() | |
response = requests.delete( | |
url, | |
headers=headers, | |
params=params or {}, | |
json=data, | |
timeout=self.options.timeout, | |
) | |
return self._process_response(response) |
Reproduction
Try the following script to do a lot of POST call. (I used adding a member to an Organization)
# =========================================================
# Step 1: Install Auth0 Phyton SDK
# =========================================================
"""
pip install auth0-python
"""
# =========================================================
# Step 2: Create M2M Application
# =========================================================
"""
1. Go to "Applications" -> "Applications" and click on "+ Create Application".
2. Enter as "Name": "SaaS Management M2M", select "Machine to Machine Applications" and click on "Create".
3. Select "Auth0 Management API" and select "All" Permissions (for production, select only the scopes that are required).
4. Click on "Authorize"
5. Switch to the tab "Settings" and copy the values of "Domain", "Client ID" and "Client Secret".
"""
# =========================================================
# Step 3: Run Deployment
# =========================================================
from auth0.authentication import GetToken
from auth0.management import Auth0
from auth0.rest import RestClientOptions
from auth0.rest import RateLimitError
import time
# Step 1: Get Access Token for Management API
auth0_domain = "domain.eu.auth0.com"
auth0_client_id = "XXXX"
auth0_client_secret = "XXXX"
get_token = GetToken(auth0_domain, auth0_client_id, client_secret=auth0_client_secret)
token = get_token.client_credentials('https://{}/api/v2/'.format(auth0_domain))
mgmt_api_token = token['access_token']
# Step 2: Create Auth0
rest_client_option = RestClientOptions(retries=10) # set max retries to maximum of 10
auth0 = Auth0(auth0_domain, mgmt_api_token, rest_client_option)
# Step 3: Loop on any API that is doing a put/post/delete call for about 30 tries,
# for me - it usually happens on try 16 or 17
for i in range(1, 30):
start_time = time.perf_counter()
print("===== Iteration "+ str(i) + " =====")
try:
organization_id = "org_V6RnNQ9x3vKcGcB9"
user_id = "auth0|64db3cf0cf71fa8ca0ae9226"
auth0.organizations.create_organization_members(organization_id, {"members":[user_id]})
except RateLimitError as e:
print("!!!!!!!!!!!! RateLimitError !!!!!!!!!!!!")
print("Time per API call: " + str(time.perf_counter() - start_time))
raise e
print("Time per API call: " + str(time.perf_counter() - start_time))
Additional context
No response
auth0-python version
4.4.0
Python version
3.11.4
Metadata
Metadata
Assignees
Labels
bugThis points to a verified bug in the codeThis points to a verified bug in the code