- Metron: 20 req/min, 5,000 req/day per IP https://metron.cloud/ — see also mokkari/session.py
- ComicVine: 1 req/sec, 200 req/hr per IP https://comicvine.gamespot.com/api/documentation — see simyan/comicvine.py
comicbox.formats.base.online.rate_limits¶
source module comicbox.formats.base.online.rate_limits
Rate limits for online sources, with per-source overrides.
The upstream libraries (mokkari for Metron, simyan for ComicVine) already enforce sensible rate limits via pyrate_limiter’s SQLite-backed bucket that persists state across runs. Comicbox inherits Metron’s default without intervention; for ComicVine it always installs its own limiter (see below).
This module exists so:
- The numbers are visible in our codebase (rather than hidden in transitive dependencies) and can be cited / audited.
- Power users with higher API tiers can raise the cap without forking their library install —
online.<source>.rate_limit.*config keys construct a custom bucket / limiter. - We can lower the cap defensively if a source ever publishes a stricter policy and we need to ship a release before the upstream library bumps its constants.
- ComicVine specifically: simyan’s limiter blocks indefinitely on an hourly-cap hit (
try_acquire(timeout=-1)), which reads as a silent, uninterruptible hang. We always wrap it so the blocking wait is bounded and long waits surface asRateLimitErrorthrough comicbox’s logged, cancellable retry layer — seebuild_comicvine_limiter/_BoundedComicVineLimiter. (mokkari already raises on its local cap, so Metron needs no such wrapper.)
Defaults match the upstream-library values as of 2026-05. For Metron’s un-overridden case the upstream library’s bucket is used (we read its value at session-construction time rather than passing our own).
Sources
Functions
-
build_metron_bucket — Construct a custom mokkari bucket from override values, or None.
-
build_comicvine_limiter — Construct comicbox’s ComicVine limiter (always non-None).
source build_metron_bucket(limits: OnlineSourceLimits | None, db_path: Path | str)
Construct a custom mokkari bucket from override values, or None.
Returns None when no overrides are set so mokkari uses its default SQLite-backed bucket (preserving cross-process / cross-run state). When any override is set, returns a process-wide memoized SQLiteBucket persisted at db_path with the per-minute and per-day rates.
Lazy-imports pyrate_limiter so callers without the override don’t pay the import cost at module load.
source build_comicvine_limiter(limits: OnlineSourceLimits | None, db_path: Path | str)
Construct comicbox’s ComicVine limiter (always non-None).
Returns a process-wide memoized _BoundedComicVineLimiter over a SQLiteBucket persisted at db_path. Override values from online.comicvine.rate_limit.* set the per-second / per-hour rates; absent overrides fall back to the documented CV defaults (1/sec, 200/hr — the same numbers simyan ships).
Unlike build_metron_bucket, this never returns None: we always install our own limiter so the blocking wait is bounded. simyan’s default limiter calls try_acquire with timeout=-1 (wait forever), turning an hourly-cap hit into a silent, uninterruptible multi-minute block. Wrapping the limiter is the only lever — pyrate_limiter 4.x dropped max_delay from the Limiter constructor, and simyan’s transport hardcodes the try_acquire call args. See _BoundedComicVineLimiter for the bounding behaviour.