-
RunEstimate — The projected cost of a batch online-tag run.
comicbox.online_estimate¶
source module comicbox.online_estimate
Estimate the API-request count and wall-clock for a batch online-tag run.
A batch caller (Codex) shows this to an operator before a “Tag Online” run and mirrors it in a live countdown. Keeping the model here — next to the search flow it describes and the rate limits it divides by — means the numbers move with comicbox’s behavior instead of drifting in a downstream copy.
The model is deliberately simple. Per comic, each source costs a characteristic number of API requests:
- Metron resolves an issue with a single
issues_listsearch plus the final issue fetch — a flat count (see v4.0.5 / PR #143; no series-discovery step since series ids land directly on issue-list results). Metron does not fan out, so effort does not move it. - Comic Vine discovers volumes, asks each surviving candidate for its issues, then fetches the issue it accepts. Only the middle step varies:
Effortdecides how many candidates are worth a call.
Match mode is not an input. It decides how a verdict is applied, never how many requests a search spends.
Under first-match-wins a comic stops at the first source that answers, so the run is billed the costliest single selected source; merging all sources (first_wins=False) queries every source per comic, so their per-comic costs are summed.
Wall-clock paces each source at its sustained throughput: Metron’s per-minute cap binds a bounded run directly. Comic Vine limits per resource pool — 200/hour for each endpoint (simyan keeps a separate bucket per endpoint, mirroring CV’s documented “200 requests per resource per hour”) — so a run is bound by its busiest single pool, not by the request total: discovery and the final fetches each land in their own pool while the per-volume issue lookups stack in one. first-match-wins means a comic isn’t done until the binding source answers, so the slowest source sets the pace; merging pays every source per comic, so their paces sum.
The projection prices a cold search for every comic. A real run batches by series, where one search answers for the whole series and the issues after it cost about one issue-list call each, so a library finishes ahead of this number. Each call counted here is one HTTP request: simyan 4.1.0 stops paginating on a short page, so a Comic Vine list call no longer spends two of its pool’s hourly budget (Simyan#309, see tasks/simyan-4-plan.md).
Classes
Functions
-
metron_requests_for_batch — Return what a Metron batch of
comicsoverseriesruns costs. -
source_rate_per_minute — Return the pace to project a run at, preferring the server’s number.
-
requests_per_comic — Return the API requests one comic costs against
sourceateffort. -
estimate_run — Project the request count and wall-clock seconds for a batch online-tag run.
source class RunEstimate()
The projected cost of a batch online-tag run.
Attributes
-
requests : int — Total API requests the run is expected to make.
-
seconds : float — Projected wall-clock duration in seconds.
source metron_requests_for_batch(comics: int, series: int) → int
Return what a Metron batch of comics over series runs costs.
The per-comic constant prices a comic that resolves its own series. That is the right number for a scattered batch and badly wrong for a library-scale one, where one series answers for a hundred comics: each series pays the cold price once and every other comic of it pays the warm price.
series is how many distinct series the batch spans — the CLI and OnlineSession.tag_many both count them to decide prefetching, so the caller has the number already. Clamped into range, since a batch cannot span more series than it has comics.
source source_rate_per_minute(source: str) → int
Return the pace to project a run at, preferring the server’s number.
SOURCE_RATE_PER_MINUTE holds documented starting points. Metron sends its real per-user burst limit on every response, and comicbox’s rate gate paces against that, so once anything has talked to Metron in this process the gate’s number is the one a projection should use — a self-hosted instance or a changed server setting makes the constant simply wrong.
source requests_per_comic(source: str, effort: str = Effort.BALANCED.value) → int
Return the API requests one comic costs against source at effort.
effort is an :class:~comicbox.config.online.settings.Effort or its value. Resolve it for the source it prices — resolve_effort(settings.online, "comicvine") — because a per-source override beats the global setting.
source estimate_run(comics: int, sources: Sequence[str], *, effort: str = Effort.BALANCED.value, merge_all_sources: bool = False) → RunEstimate
Project the request count and wall-clock seconds for a batch online-tag run.
comics is how many comics remain to look up and sources the enabled source names in priority order. effort is an :class:~comicbox.config.online.settings.Effort value ("balanced" etc.), resolved for the source it prices. merge_all_sources mirrors first_wins=False: every source is queried per comic and their per-comic costs summed, instead of stopping at the first match.
The projection assumes the effort it is handed. A CLI run can auto-engage a lower Comic Vine effort for a large unattended batch, which this cannot see.