From 7a91acb60ca1ea0e18c1f3157d876c8c6ef3733d Mon Sep 17 00:00:00 2001 From: Mizaki Date: Tue, 20 Jun 2023 22:28:29 +0100 Subject: [PATCH] Add pyrate-limiter and apply CV suggested rate limit --- comictalker/talkers/comicvine.py | 31 +++++++++++++++++++------------ setup.cfg | 1 + 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/comictalker/talkers/comicvine.py b/comictalker/talkers/comicvine.py index 337828c..d53e290 100644 --- a/comictalker/talkers/comicvine.py +++ b/comictalker/talkers/comicvine.py @@ -26,6 +26,7 @@ from urllib.parse import urljoin import requests import settngs +from pyrate_limiter import Limiter, RequestRate from typing_extensions import Required, TypedDict import comictalker.talker_utils as talker_utils @@ -152,6 +153,10 @@ class CVResult(TypedDict, Generic[T]): CV_STATUS_RATELIMIT = 107 +# https://comicvine.gamespot.com/forums/api-developers-2334/api-rate-limiting-1746419/ +# "Space out your requests so AT LEAST one second passes between each and you can make requests all day." +limiter = Limiter(RequestRate(1, 2)) + class ComicVineTalker(ComicTalker): name: str = "Comic Vine" @@ -428,27 +433,29 @@ class ComicVineTalker(ComicTalker): return formatted_filtered_issues_result + @limiter.ratelimit("cv", delay=True) def _get_cv_content(self, url: str, params: dict[str, Any]) -> CVResult: """ - Get the content from the CV server. If we're in "wait mode" and status code is a rate limit error - sleep for a bit and retry. + Get the content from the CV server. We should never hit a rate limit but will cover it anyway. """ - total_time_waited = 0 - limit_wait_time = 1 counter = 0 - wait_times = [1, 2, 3, 4] while True: cv_response: CVResult = self._get_url_content(url, params) - if self.wait_on_ratelimit and cv_response["status_code"] == CV_STATUS_RATELIMIT: - logger.info(f"Rate limit encountered. Waiting for {limit_wait_time} minutes\n") - time.sleep(limit_wait_time * 60) - total_time_waited += limit_wait_time - limit_wait_time = wait_times[counter] + + if cv_response["status_code"] == CV_STATUS_RATELIMIT: + logger.info("Rate limit encountered. Waiting for 10 seconds\n") + time.sleep(10) if counter < 3: counter += 1 - # don't wait much more than 20 minutes - if total_time_waited < self.wait_on_ratelimit_time: continue + # Tried 3 times, inform user to check CV website. + logger.error("Rate limit error. Exceeded 3 retires.") + raise TalkerNetworkError( + self.name, + 3, + "Rate Limit Error: Check your current API usage limit at https://comicvine.gamespot.com/api/", + ) + if cv_response["status_code"] != 1: logger.debug( f"{self.name} query failed with error #{cv_response['status_code']}: [{cv_response['error']}]." diff --git a/setup.cfg b/setup.cfg index 4fdc2b6..8f51483 100644 --- a/setup.cfg +++ b/setup.cfg @@ -40,6 +40,7 @@ install_requires = pathvalidate pillow>=9.1.0,<10 pycountry + pyrate-limiter rapidfuzz>=2.12.0 requests==2.* settngs==0.7.1