Handle errors in RequestExecutionQueue#47107
Handle errors in RequestExecutionQueue#47107davidwengier merged 21 commits intodotnet:features/lspClassificationsfrom
Conversation
src/VisualStudio/Core/Def/Implementation/LanguageClient/InProcLanguageServer.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/LanguageClient/InProcLanguageServer.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
skipped this for now.
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/Protocol/AbstractRequestHandlerProvider.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/LanguageClient/InProcLanguageServer.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/LanguageClient/InProcLanguageServer.cs
Outdated
Show resolved
Hide resolved
jasonmalinowski
left a comment
There was a problem hiding this comment.
It looks like there's one potential issue where DequeueAsync() could raise cancellation during the shutdown process and we might treat that as a reportable error even though things are good.
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
So now that we're having to do these catches anyways, does do we really need the ranToCompletion boolean as well? If instead work.CallbackAsync just returns the same task from the TaskCompletionSource it returned to the original caller, then you can just simplify this to:
try
{
await work.CallbackAsync(....);
lastMutatedSolution = mutatedSolution ?? lastMutatedSolution;
}
catch (OperationCanceledException)
{
}
catch (Exception e)
{
OnRequestServerShutdown($"An error occured processing a mutating request and the solution is in an invalid state. Check LSP client logs for any error information.");
}
Which also means you now have the exception in hand if you want to pass a message back to the OnRequestServerShutdown rather than eating the exception if the logs are unavailable.
There was a problem hiding this comment.
This could work, but I don't think I'm a big fan because the Callback will have to catch and rethrow the exceptions, and I think it will generally be harder to understand what is going on. You're right it would make for a better log message, which might be useful.
src/VisualStudio/Core/Def/Implementation/LanguageClient/InProcLanguageServer.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
eec6398 to
2e77925
Compare
|
Ping @sharwell @jasonmalinowski all feedback has been addressed, except the bool return from the callback. |
jasonmalinowski
left a comment
There was a problem hiding this comment.
I think this looks OK from the threading perspective (modulo some comments), although I'm still cautious about what the merging logic is ultimately going to look like. Depending on how it ultimately works this RequestExecutionQueue implementation can be greatly simplified (I think) with the pattern we use other parts of Roslyn where we just have a queue of Tasks created with ContinueWith calls; the non-mutating in that case are just tasks that branch off and don't actually get placed in the queue. I think that approach gets us the error handling and cancellation logic automatically. But that's very much contingent on how that "TODO" comment gets resolved!
I admit the big picture of how an ILspSolutionProvider vs. AbstractRequestHandlerProvider vs. AbstractLanguageServerClient isn't clear to me, and although that's not the doing of this pull request it means I can't say with any confidence whether the changes to that structure here are right. So hopefully somebody else can confirm that bit. 😄
src/Features/LanguageServer/Protocol/Handler/RequestExecutionQueue.cs
Outdated
Show resolved
Hide resolved
src/EditorFeatures/TestUtilities/LanguageServer/AbstractLanguageServerProtocolTests.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/ProtocolUnitTests/Definitions/GoToDefinitionTests.cs
Outdated
Show resolved
Hide resolved
src/Features/LanguageServer/ProtocolUnitTests/Ordering/RequestOrderingTests.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Test.Next/Services/LspDiagnosticsTests.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/LanguageClient/InProcLanguageServer.cs
Show resolved
Hide resolved
Indeed, I was originally expecting the "merge" to be complicated but I think it might end up being relatively simple so some of this could be looked at again. We're still working out what exactly the merge will do though :) |
Fixes #46051
This PR is the "final" piece of request queue stuff, except merging the solutions.
This introduces error handling in the request queue including sending back a message to the client and disconnecting. I've tested this in Live Share and the client reconnects silently when it next needs to, and correctly calls Initialize and everything continues as expected.
This also changes the lifetime of the RequestExecutionQueue so its not a MEF component, but is directly constructed by each server. In addition the queue is used directly from the InProcLanguageServer instead of going through the AbstractRequestHandlerProvider, though it still needs to know about it.