Expand description
Run CPU-bound handler work off the async runtime worker.
tower-lsp drives every connection’s requests from the same small tokio
worker pool. A handler that walks an AST, scans the workspace index, or
shells out to an external process inline blocks that worker — every
other in-flight request (on this connection or, with a multi-threaded
runtime, any other task sharing the pool) stalls until it finishes. See
the git history for the long tail of fix(lsp): run X off the request loop commits this fixed one handler at a time before this module existed.
run and run_gated are the two sanctioned ways to leave the async
runtime worker: tokio::task::spawn_blocking plus uniform panic
handling. A spawn_blocking panic is delivered as Err(JoinError)
rather than propagating like a normal panic; before this module several
call sites discarded that Err via .unwrap_or_default() with no
logging at all, so a panicking closure failed silently. Both helpers log
unconditionally and return None, so callers can never reintroduce that
gap by accident — .unwrap_or_default(), .unwrap_or(fallback), and
let Some(x) = ... else { return .. } all stay available on the
Option they return.
run_gated additionally passes through a named DebugGate
section first, so a responsiveness regression test can pin that specific
closure in flight and assert the connection still answers other requests
meanwhile (see debug_gate module docs). Reach for run when a closure
has no such test.