mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
fix: wait out a 429 and keep the pass going
A single 429 from git.libretro.com on cemu's tree ended profile_sync --all with a traceback and no report for the other 646 profiles. upstream now waits a 429 out (Retry-After up to 120 s, else 5, 20, 60 s), as base_scraper already did, and stops asking a host that outlasts the waits. profile_sync reports that profile as rate limited, fails the run, and carries on with the other forges.
This commit is contained in:
1 parent
f2faf4d9ed
commit
d458cf653a
4 files changed
+198
-53
No files matched your search
+44
-3
@@ -237,9 +237,11 @@ class TestFetchRetry(unittest.TestCase):
|
||||
self._orig = (urllib.request.urlopen, upstream._sleep)
|
||||
self.slept: list[float] = []
|
||||
upstream._sleep = self.slept.append
|
||||
upstream._exhausted_hosts.clear()
|
||||
|
||||
def tearDown(self):
|
||||
urllib.request.urlopen, upstream._sleep = self._orig
|
||||
upstream._exhausted_hosts.clear()
|
||||
|
||||
def _serve(self, outcomes):
|
||||
self.calls = 0
|
||||
@@ -283,11 +285,50 @@ class TestFetchRetry(unittest.TestCase):
|
||||
self.assertIsNone(upstream._fetch("https://host/x"))
|
||||
self.assertEqual(self.calls, 1)
|
||||
|
||||
def test_rate_limit_is_not_retried(self):
|
||||
self._serve([_http_error(429)])
|
||||
@staticmethod
|
||||
def _limited(retry_after: str | None = None) -> urllib.error.HTTPError:
|
||||
import email.message # noqa: PLC0415
|
||||
|
||||
headers = email.message.Message()
|
||||
if retry_after is not None:
|
||||
headers["Retry-After"] = retry_after
|
||||
return _http_error(429, headers)
|
||||
|
||||
def test_rate_limit_is_waited_out(self):
|
||||
# git.libretro.com answered 429 on cemu's tree a few hundred
|
||||
# requests into a pass, and the whole pass stopped.
|
||||
self._serve([self._limited("7"), self._limited(), b"payload"])
|
||||
self.assertEqual(upstream._fetch("https://host/x"), b"payload")
|
||||
self.assertEqual(self.slept, [7.0, upstream.RATE_LIMIT_WAITS[1]])
|
||||
|
||||
def test_lasting_rate_limit_mutes_the_host_only(self):
|
||||
self._serve([self._limited()])
|
||||
with self.assertRaises(upstream.RateLimitError) as caught:
|
||||
upstream._fetch("https://host/x")
|
||||
self.assertEqual(caught.exception.host, "host")
|
||||
self.assertEqual(self.calls, len(upstream.RATE_LIMIT_WAITS) + 1)
|
||||
# The same host is not asked again, another one still is.
|
||||
with self.assertRaises(upstream.RateLimitError):
|
||||
upstream._fetch("https://host/y")
|
||||
self.assertEqual(self.calls, len(upstream.RATE_LIMIT_WAITS) + 1)
|
||||
self._serve([b"other"])
|
||||
self.assertEqual(upstream._fetch("https://other/x"), b"other")
|
||||
|
||||
def test_long_retry_after_is_not_waited(self):
|
||||
self._serve([self._limited(str(int(upstream.RATE_LIMIT_WAIT_CAP) + 1))])
|
||||
with self.assertRaises(upstream.RateLimitError):
|
||||
upstream._fetch("https://host/x")
|
||||
self.assertEqual(self.calls, 1)
|
||||
self.assertEqual((self.calls, self.slept), (1, []))
|
||||
|
||||
def test_exhausted_github_quota_is_not_waited(self):
|
||||
import email.message # noqa: PLC0415
|
||||
|
||||
headers = email.message.Message()
|
||||
headers["X-RateLimit-Remaining"] = "0"
|
||||
self._serve([_http_error(403, headers)])
|
||||
with self.assertRaises(upstream.RateLimitError):
|
||||
upstream._fetch("https://host/x")
|
||||
self.assertEqual((self.calls, self.slept), (1, []))
|
||||
|
||||
|
||||
class TestGoneUpstream(unittest.TestCase):
|
||||
|
||||
Reference in new issue
Block a user