Skip to content

Commit 015b95d

Browse files
committed
fix(verify): cap the per-host rate-limit backoff
The rate-limit penalty added in #52 is multiplicative with no ceiling, so a host that refuses repeatedly walks its interval up without bound (1s -> 4 -> 16 -> 64 -> ...). Over the ~4,000 cited GSMArena URLs that turns a run into hours of sleeping and risks the job timeout. Cap the per-host interval at 30s. Refs #1
1 parent 4da91fc commit 015b95d

2 files changed

Lines changed: 12 additions & 1 deletion

File tree

app/verify/http_check.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
MAX_RETRY_AFTER_S = 15.0
4242
# How much to slow a host down for the rest of the run once it has pushed back.
4343
RATE_LIMIT_PENALTY = 4.0
44+
# The penalty is multiplicative, so without a ceiling a host that refuses often
45+
# walks the interval up without bound (1s -> 4 -> 16 -> 64 -> ...) and a run over
46+
# a few thousand URLs on that host turns into hours of sleeping.
47+
MAX_HOST_INTERVAL_S = 30.0
4448

4549

4650
class CheckResult(NamedTuple):
@@ -184,7 +188,7 @@ def back_off(self, host: str, factor: float = RATE_LIMIT_PENALTY) -> None:
184188
pace and every subsequent URL on it comes back 429.
185189
"""
186190
with self._lock:
187-
self._interval[host] = self.interval_for(host) * factor
191+
self._interval[host] = min(self.interval_for(host) * factor, MAX_HOST_INTERVAL_S)
188192

189193
def wait(self, host: str) -> None:
190194
with self._lock:

tests/verify/test_http_check.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,10 @@ def test_cached_rate_limit_entries_are_not_cache_hits(tmp_path):
167167
cache = http_check.load_cache(path)
168168
assert "https://en.wikipedia.org/wiki/X" in cache
169169
assert "https://www.gsmarena.com/a-1.php" not in cache # a 429 is not an answer
170+
171+
172+
def test_host_backoff_is_capped():
173+
limiter = http_check.HostRateLimiter(min_interval=1.0)
174+
for _ in range(20):
175+
limiter.back_off("gsmarena.com")
176+
assert limiter.interval_for("gsmarena.com") == http_check.MAX_HOST_INTERVAL_S

0 commit comments

Comments
 (0)