Skip to content

Conversation

MichaReiser
Copy link
Member

@MichaReiser MichaReiser commented Jul 31, 2025

Summary

This PR implements long-polling for workspace diagnostics (as described in the spec).

Without long polling, VS Code keeps sending workspace/diagnostic requests every 2 seconds, even if the user didn't make any changes. This can take up a fair amount of CPU usage, even if all diagnostics are cached, because we still need to iterate over all files.

This PR implements long polling which avoids this. The basic idea is that the server keeps the workspace/diagnostic open and only responds once there are changes (e.g. new or fixed diagnostics) or the server shuts down (or cancels the request).

Implementing this required adding a process method to the request handler in order that workspace diagnostics can omit the response when long polling.

This PR implements the last optimization mentioned in astral-sh/ty#824

Closes astral-sh/ty#824

I can no longer reproduce astral-sh/ty#818 on this PR (closes astral-sh/ty#818)

Test Plan

Added integration tests

Screen.Recording.2025-08-01.at.17.38.34.mov
Screen.Recording.2025-08-01.at.17.39.13.mov

@MichaReiser MichaReiser added server Related to the LSP server ty Multi-file analysis & type inference labels Jul 31, 2025
Copy link
Contributor

github-actions bot commented Jul 31, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

Copy link
Contributor

github-actions bot commented Aug 1, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

api::request(request);
tracing::debug!("Retrying request {}/{}", request.method, request.id);
let task = api::request(request);
scheduler.dispatch(task, &mut self.session, client);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whooops

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh lol, is it that the request were never retried before this PR then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes 😅

@MichaReiser MichaReiser force-pushed the micha/diagnostic-streaming branch from 79178da to 2995687 Compare August 1, 2025 15:43
@MichaReiser MichaReiser requested a review from dhruvmanila August 1, 2025 15:44
@MichaReiser MichaReiser marked this pull request as ready for review August 1, 2025 15:44
Copy link
Contributor

github-actions bot commented Aug 1, 2025

mypy_primer results

No ecosystem changes detected ✅
No memory usage changes detected ✅

@AlexWaygood AlexWaygood removed their request for review August 1, 2025 16:11
Copy link
Member

@dhruvmanila dhruvmanila left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome! Thank you for taking on the entire performance improvement part of workspace diagnostics!

api::request(request);
tracing::debug!("Retrying request {}/{}", request.method, request.id);
let task = api::request(request);
scheduler.dispatch(task, &mut self.session, client);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh lol, is it that the request were never retried before this PR then?


// Make a workspace diagnostic request to a project with one file but no diagnostics
// This should trigger long-polling since the project has no diagnostics
let request_id = send_workspace_diagnostic_request(&mut server);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we update the workspace_diagnostic_request method on TestServer with more parameters like the progress params, partial result params, etc. instead of adding another function here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I sort of prefer test-local helpers because the method on TestServer otherwise has to accept a WorkspaceDiagnosticParams to support all combinations, in which case it is about as verbose as calling the method directly. What I can do is to give this function a better name

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could update the parameters on the server method to accept the parts of WorkspaceDiagnosticParams instead but I'm fine either way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I now remember why it is necessary. The key difference is that this method doesn't await the response because we need to handle the response specially (it's long polling)

@MichaReiser MichaReiser force-pushed the micha/diagnostic-streaming branch from 2995687 to 54a2995 Compare August 4, 2025 08:58
Base automatically changed from micha/diagnostic-streaming to main August 4, 2025 09:34
@MichaReiser MichaReiser enabled auto-merge (squash) August 4, 2025 10:16
@MichaReiser MichaReiser merged commit f473f6b into main Aug 4, 2025
37 checks passed
@MichaReiser MichaReiser deleted the micha/long-polling branch August 4, 2025 10:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
server Related to the LSP server ty Multi-file analysis & type inference
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support streaming and caching for workspace diagnostics Stale diagnostics when file is deleted in workspace diagnostic mode
2 participants