Coverage for src/local_deep_research/settings/env_definitions/server.py: 100%
3 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-22 21:20 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-22 21:20 +0000
1"""
2Server runtime environment settings.
4These settings control server-level parameters that require a restart
5to take effect. They are not editable via the UI.
6"""
8from ..env_settings import BooleanSetting, IntegerSetting
10TRUSTED_PROXY_COUNT = IntegerSetting(
11 key="server.trusted_proxy_count",
12 description=(
13 "Number of X-Forwarded-For entries your trusted reverse proxies "
14 "append -- one per appending hop for an ordinary proxy, so CDN -> "
15 "nginx is 2. Used by the rate limiter only while "
16 "TRUST_PROXY_HEADERS is NOT set: it then reads the N-th entry from "
17 "the right, provided the direct peer is private/loopback or, once "
18 "a restricted LDR_SERVER_FORWARDED_ALLOW_IPS is set, listed there "
19 "(otherwise it keys on the direct peer). N must be exact: too "
20 "small keys every client on a proxy's address, too large reads an "
21 "entry the client wrote itself (or, when the header is shorter "
22 "than N, keys on the direct peer). Zero (default) disables hop "
23 "counting and keeps the single-proxy behaviour (the right-most "
24 "entry). With TRUST_PROXY_HEADERS=true this value has no effect -- "
25 "list every hop in LDR_SERVER_FORWARDED_ALLOW_IPS instead -- and "
26 "setting it while that allow-list still trusts every peer (the "
27 'default "*") makes LDR refuse to start. For N >= 2, every '
28 "intermediate hop must be unreachable directly by clients, or a "
29 "client connecting to an inner hop chooses the entry read. Does not "
30 "affect X-Forwarded-Proto/scheme detection. See 'Proxy chains' in "
31 "docs/deployment/reverse-proxy.md. Accepted values are ASCII "
32 "decimal integers from 0 to 16 (surrounding whitespace is ignored "
33 "and -0 reads as 0); an empty or whitespace-only value counts as "
34 "unset, and any other invalid value prevents startup."
35 ),
36 min_value=0,
37 # A real deployment has one or two hops in front of LDR; a CDN plus a
38 # tunnel plus an ingress is three or four. 16 sits far above anything
39 # operationally sensible while still turning a fat-fingered value (a
40 # pasted port number, a year) into a startup failure that names the
41 # variable -- instead of a hop count no X-Forwarded-For chain can
42 # satisfy, which would silently collapse every client behind the proxy
43 # into the direct peer's single rate-limit bucket.
44 max_value=16,
45 default=0,
46 raise_on_validation_error=True,
47 # Reject "1_0" (int() reads that as 10), "+3", and non-ASCII decimal
48 # digits such as "٣": a trust-boundary count must mean what it
49 # looks like.
50 strict_digits=True,
51)
54SERVER_SETTINGS = [
55 IntegerSetting(
56 key="server.max_concurrent_research",
57 description="Server-wide maximum concurrent research operations. Requires restart.",
58 min_value=1,
59 max_value=1000,
60 default=10,
61 deprecated_env_var="LDR_MAX_GLOBAL_CONCURRENT",
62 ),
63 IntegerSetting(
64 key="web.threadpool_max_threads",
65 description=(
66 "Maximum AnyIO worker threads serving synchronous route "
67 "handlers. Leave unset to use AnyIO's default of 40. Every "
68 "plain `def` route occupies one worker for its whole duration, "
69 "and the pool is shared with async dependency solving and "
70 "response validation, so exhausting it slows async routes too. "
71 "Raise it if concurrent requests queue behind each other under "
72 "load; each extra thread costs context switching and contends "
73 "for the same per-user database pool. Requires restart."
74 ),
75 min_value=1,
76 max_value=1000,
77 default=None,
78 ),
79 BooleanSetting(
80 key="vite.dev_mode",
81 description=(
82 "When true, templates link to the Vite dev server at "
83 "http://localhost:5173 for HMR instead of the built manifest "
84 "under static/dist. Set to true when running `npm run dev` "
85 "alongside the Python server."
86 ),
87 default=False,
88 ),
89 TRUSTED_PROXY_COUNT,
90]