-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[ty] Gracefully handle salsa cancellations and panics in background request handlers #18254
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
09d5dbc to
3f64170
Compare
|
|
||
| /// Checks all open files in the project and its dependencies. | ||
| pub fn check(&self) -> Result<Vec<Diagnostic>, Cancelled> { | ||
| pub fn check(&self) -> Vec<Diagnostic> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to remove all Results from here for now because the server already uses many salsa APIs that aren't wrapped in a salsa::Cancelled::catch. Instead, I decided that the server request handlers catch salsa cancellations (only necessary for background tasks because:
- Only local tasks can mutate the DB
- All local tasks run on the main loop thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not hugely familiar with this part of the code, but this rationale sounds reasonable
| let (id, params) = cast_request::<R>(req)?; | ||
| Ok(Task::local(|session, notifier, requester, responder| { | ||
| let _span = tracing::trace_span!("request", %id, method = R::METHOD).entered(); | ||
| let _span = tracing::debug_span!("request", %id, method = R::METHOD).entered(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The span is very useful and tracing is just way too verbose.
crates/ty_server/src/server/api.rs
Outdated
| Ok(response) => Some(response), | ||
| Err(error) => { | ||
| if error.payload.downcast_ref::<salsa::Cancelled>().is_some() { | ||
| // Request was cancelled by Salsa. TOOD: Retry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I leave this for another PR, there's already enough going on in this PR
|
|
|
||
| /// Checks all open files in the project and its dependencies. | ||
| pub fn check(&self) -> Result<Vec<Diagnostic>, Cancelled> { | ||
| pub fn check(&self) -> Vec<Diagnostic> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not hugely familiar with this part of the code, but this rationale sounds reasonable
dhruvmanila
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
| let message = format!("request handler {error}"); | ||
|
|
||
| Some(Err(Error { | ||
| code: lsp_server::ErrorCode::InternalError, | ||
| error: anyhow!(message), | ||
| })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we could probably use LSPResult::with_failure_code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I didn't know about this method. I'll leave it as is because I use the lsp_server Error type in #18273
| // The new PanicInfoHook name requires MSRV >= 1.82 | ||
| #[expect(deprecated)] | ||
| type PanicHook = Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>; | ||
| type PanicHook = Box<dyn Fn(&PanicHookInfo<'_>) + 'static + Sync + Send>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make this change for ruff_server as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I plan to backport this entire stack to ruff
8fcdf96 to
ccd14a5
Compare
3f64170 to
836fc57
Compare
836fc57 to
3fe52c6
Compare
Summary
Run the request and notification handlers in a
catch_unwindthat ensures that a handler failure doesn't tear down the entire server process. ty now also responds with an appropriate error instead of just never responding to the client's request. This has the advantage that e.g. VS code stops sending new diangostic pull requests for a file on which the server crashed before.I considered wrapping local notifications handlers in
catch_unwindbut decided against it. Local notifications are used to update the server state. An out of date server state can lead to all sort of errors because the ranges are of. That's why I think it's better to still crash the server.Test Plan