Why Warmup is Needed
After spawning, LSP backends (pyright, ty, pyrefly) need time to build their cross-file index. Requests sent during this warmup period return incomplete results:During Warmup (Incomplete)
findReferencesreturns same-file only (missing cross-project references)goToDefinitionon re-exported symbols returns empty- Type errors not detected if symbol defined in another file
After Warmup (Complete)
findReferencesreturns all references across the projectgoToDefinitionfollows imports and re-exports correctly- Full type checking with cross-file dependencies
Real-World Example
- Problem: Sent Too Early
- Safe: Non-Index Requests
- User opens
auth.py→ backend spawned (warming) - User immediately clicks “Find References” on
get_name - Backend hasn’t indexed
user.pyyet - Result: Only shows reference in
auth.py(incorrect!)
- User opens
auth.py→ backend spawned (warming) - User clicks “Find References” on
get_name→ queued - Backend finishes indexing (2s later) → transitions to Ready
- Queued request forwarded to backend
- Result: Shows references in both
auth.pyanduser.py(correct!)
Warming vs Ready States
Each backend instance tracks its warmup state in the pool.State Definitions
Code reference:src/backend_pool.rs:13-21
State Transition Diagram
Transition Triggers
1
Spawn (→ Warming)
New backend starts in
Warming state (unless timeout is 0).Code reference: src/proxy/client_dispatch.rs:55-612
Progress Signal (→ Ready)
Backend sends Progress detection:
$/progress notification with kind: "end".Code reference: src/proxy/backend_dispatch.rs:110-1343
Timeout Expiry (→ Ready, Fail-Open)
If progress signal never arrives, fail-open after timeout.Code reference: Why fail-open? If backend never signals readiness (bug, slow machine, etc.), better to forward requests (potentially incomplete results) than block forever.
src/proxy/pool_management.rs:264-302Which Requests are Queued
Only index-dependent requests are queued during warmup.Queued Methods (Index-Dependent)
Code reference:src/proxy/client_dispatch.rs:11-17
Forwarded Immediately (Not Queued)
Queueing Logic
Code reference:src/proxy/client_dispatch.rs:337-359
Timeout Behavior
Default Timeout
2 seconds (configurable viaTYPEMUX_CC_WARMUP_TIMEOUT).
Code reference: src/backend_pool.rs:24-34
Timeout Event Loop Arm
The main event loop has a dedicated arm for warmup expiry: Code reference:src/proxy/mod.rs (conceptual, see actual source)
nearest_warmup_deadline() to sleep until the soonest backend expires. This avoids polling and ensures immediate transition when timeout occurs.
Timeout Scenarios
- Fast Backend (< 2s)
- Slow Backend (> 2s)
- No Queued Requests
Configuration
Environment Variable
Configuration Examples
Config File Setup
For persistent configuration:When to Disable Warmup
Use cases for disabling:- Testing/debugging: Simpler behavior, no queuing logic
- Pre-indexed backends: If you know the backend re-uses a persistent index (some LSP servers cache indexes on disk)
- Single-file workflows: If you never use cross-file features (references, implementations)
Queue Behavior Details
Queue Structure
Each backend maintains a FIFO queue of pending requests. Code reference:src/backend_pool.rs:54
Draining the Queue
When transitioning to Ready, queued requests are drained in order and forwarded to the backend. Code reference:src/backend_pool.rs:72-83
src/proxy/client_dispatch.rs:491-555
Queue Cancellation
If the user cancels a queued request via$/cancelRequest:
Code reference: src/proxy/client_dispatch.rs:463-487
- If request is in warmup queue → remove from queue (never forwarded to backend)
- If request already forwarded → forward cancel to backend
Session Guard During Drain
If a backend crashes while draining and is replaced with a new session:Monitoring Warmup Activity
Enable Debug Logging
Useful Log Queries
Real-Time Monitoring
Performance Impact
Overhead
- Latency: +2s max for index-dependent requests (only once per backend spawn)
- Memory: ~1 KB per queued request (typically 0-5 requests)
- CPU: Negligible (queue is a simple Vec)
Benefits
- Correctness: Ensures complete results for cross-file queries
- UX: Prevents confusing partial results (“why didn’t it find this reference?”)
- Reliability: Fail-open means no indefinite blocking