1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//! Request traffic class — `Interactive` (single `/scrape`) vs `Batch`
//! (batch-scrape / crawl jobs) — carried via a task-local so every shared
//! concurrency chokepoint (per-host limiter, render pool, extract pool, PDF
//! parse pool, LLM calls) can reserve a protected lane for interactive traffic
//! without threading a parameter through dozens of signatures.
//!
//! Lives in `crw-core` (not `crw-renderer`) deliberately: `crw-renderer`
//! depends on `crw-extract`, so an LLM-lane read of a `crw-renderer`-owned
//! task-local would form a dependency cycle. `crw-core` is a dependency of all
//! three, so every lane can read it.
//!
//! The class is set by the JOB ENTRY POINT, not the wire request — there is no
//! deserialized field a client could set to jump the interactive reserve. A
//! single scrape leaves the task-local unscoped and reads back `Interactive`
//! via [`current_scrape_class`]'s default; batch/crawl jobs wrap their work in
//! `REQUEST_CLASS.scope(ScrapeClass::Batch, …)` INSIDE the spawned task (a
//! handler-level scope would be lost across the job's `tokio::spawn`).
/// Traffic class for a scrape. `Interactive` is the protected default.
task_local!
/// The current task's [`ScrapeClass`], or [`ScrapeClass::Interactive`] when the
/// task-local is not in scope (every direct single-scrape caller). MUST be
/// called on the async side, before any `spawn_blocking` — the task-local is
/// not visible inside a blocking closure.