Skip to content

perf(lsp): stop cancelled requests, and run diagnostics, completions and formatting off the runtime - #954

Open
psteinroe wants to merge 2 commits into
perf/bound-walk-cache-memoryfrom
perf/cancel-editor-requests
Open

psteinroe wants to merge 2 commits into
perf/bound-walk-cache-memoryfrom
perf/cancel-editor-requests

Conversation

@psteinroe

@psteinroe psteinroe commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #953.

Two gaps that #931 left.

$/cancelRequest

When a client cancels a request, tower-lsp drops its future, but the handler kept running on the blocking pool until it finished. On a long file that is seconds of wasted work per cancelled hover, inlay hint or semantic token request, often while the next request for the same document waits for the walk cache.

  • New pgls_workspace::cancellation: with_cancellation(flag, f) sets a flag for the thread that runs f.
  • The editor walk checks it every 64 statements, together with the document version, and stops.
  • run_document_request in the LSP sets the flag when its future is dropped, whether it finished or was cancelled.
  • This only works with the workspace server in the same process. Through the daemon transport, requests still run to the end.

The documents lock

pull_file_diagnostics, pull_file_formatting, get_completions, fix_file and execute_statement held the read lock of all documents while they ran, so an edit to any document waited for them. Like hover and inlay hints in #931, they now clone the document's Arc and release the lock. In the LSP, diagnostics run with spawn_blocking, and completions and formatting go through run_document_request: blocking pool, cancellation, and ContentModified if the document changed meanwhile.

Tests

  • cancellation unit test: the flag applies while the request runs, nests, and is restored.
  • test_cancelled_requests_stop_walking: a cancelled semantic-token request returns nothing, and the next one returns all tokens.
  • The LSP test server's per-request timeout goes from 1 s to 30 s. With the work off the runtime, the timeout now measures wall time, and diagnostics against the database took longer than 1 s while the other tests ran. A hang still fails the test.
  • LSP, CLI and workspace suites pass.

Not covered

  • Cancelling a request only stops the editor walk. The analyser behind diagnostics and lint code actions, and completions, still run to the end.
  • No LSP-level test that sends $/cancelRequest. The test client can't cancel a request it awaits; the flag is tested at the workspace level.

…and formatting off the runtime

When the client cancels a request, the language server now tells the
handler to stop through a cancellation flag that the editor walk checks
with the document version. Diagnostics, completions, formatting, fixes
and statement execution no longer hold the documents lock while they
run, and diagnostics, completions and formatting run on the blocking
thread pool like hover and the other editor requests.
Diagnostics and completions now run on the blocking thread pool, so the
runtime is free while they run and the timeout of the test server fires
after one second of wall time, which diagnostics against the database
exceed while the other tests run. Allow 30 seconds; a hang still fails.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant