-
Notifications
You must be signed in to change notification settings - Fork 199
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
Move RazorWorkspaceListener to AsyncBatchingWorkQueue #10480
Conversation
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.
Putting everything in a batch is probably much better for reliability than what we were doing before. There are still going to be disk contention problems though -- it won't cure them completely. In my mind, the solutions for that would be one of:
- Process synchronization when writing reading from disk via a named mutex shared between the process this is loaded in and
rzls
. However, we should ensure that there's one mutex per Roslyn LSP/Razor LSP process pair to avoid sharing the same mutex between different VS Code instances. - Avoid the disk altogether by serializing to a named
MemoryMapFile
and somehow passing that name to the Razor LSP, which would delete it after deserializing. - Wait for co-hosting. 😄
src/Razor/src/Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace/PublicAPI.Unshipped.txt
Outdated
Show resolved
Hide resolved
...azor/src/Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace/RazorWorkspaceListener.cs
Outdated
Show resolved
Hide resolved
...azor/src/Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace/RazorWorkspaceListener.cs
Outdated
Show resolved
Hide resolved
...azor/src/Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace/RazorWorkspaceListener.cs
Outdated
Show resolved
Hide resolved
...azor/src/Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace/RazorWorkspaceListener.cs
Outdated
Show resolved
Hide resolved
...azor/src/Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace/RazorWorkspaceListener.cs
Outdated
Show resolved
Hide resolved
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
private void RemoveProject(Project? project) |
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.
It's a little worrisome that we drop project removes on the floor. We definitely watch for deletions of the project.razor.bin
file in the language server. If a project is deleted from disk, do we leave the language server in a descent state? Or, does that project continue to live there with all of its documents and references, responding to Rename, Component search, completion, etc.?
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.
This never handled removing the file, it just stopped the queue. I'm not actually sure what handles cleanup. Since we're working on _workspace.CurrentSolution
I'm guessing it would be safe to just delete the file when a project is removed?
That's new, and maybe it's already done somewhere else? Not sure
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.
One thought:
We could enqueue and update for the removed ProjectId
and in the ABWQ work method we could clean up the file if it exists and the project is no longer in the solution?
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.
This was probably unnecessary originally, but yeah I was just trying to remove the scheduler. We'd never get any more updates for the project anyway, so could have ignored removes then too.
Not sure I like the idea of removing the file though. I think in VS Code we are more likely to be processing requests before the file is written, so it does serve more like an offline cache, even if it is one that won't be being updated any more.
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.
Yeah, I agree that this is probably OK. I saw all of the red and notice that all it did was get rid of the scheduler before. With #10475 I think VS Code will start reading in .bin
even sooner, so you're right that VS Code will use it more as a cache.
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.
Test failures lead to one thing remove did that I didn't notice: we only queue work for items that have been reported with NotifyDynamicFile
. This PR breaks that. I'm adding remove back to fix
...azor/src/Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace/RazorWorkspaceListener.cs
Outdated
Show resolved
Hide resolved
...azor/src/Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace/RazorWorkspaceListener.cs
Outdated
Show resolved
Hide resolved
...azor/src/Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace/RazorWorkspaceListener.cs
Outdated
Show resolved
Hide resolved
Yea. Disk contention is attempted to be reduced by writing to a temp file and then moving it to the final file. This is done in Lines 144 to 150 in d8690ff
|
} | ||
|
||
public void Dispose() | ||
// Protected for testing | ||
#pragma warning disable RS0016 // Add public types and members to the declared API |
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.
Suppressing until I can figure out if it's user error or analyzer error.
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.
Seems like neither. A protected method of a public type is part of the public API. I'd either remove the suppression, or create a TestAccessor so it doesn't need to be protected.
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.
Is this a case where private protected
is needed?
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.
Yes! That's exactly what I was thinking. I just got my newfangled things mixed up
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
private void RemoveProject(Project? project) |
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.
This was probably unnecessary originally, but yeah I was just trying to remove the scheduler. We'd never get any more updates for the project anyway, so could have ignored removes then too.
Not sure I like the idea of removing the file though. I think in VS Code we are more likely to be processing requests before the file is written, so it does serve more like an offline cache, even if it is one that won't be being updated any more.
} | ||
|
||
public void Dispose() | ||
// Protected for testing | ||
#pragma warning disable RS0016 // Add public types and members to the declared API |
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.
Seems like neither. A protected method of a public type is part of the public API. I'd either remove the suppression, or create a TestAccessor so it doesn't need to be protected.
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.
With question about removes answered, this looks good to me!
Two major changes being introduced: dotnet/razor#10480 moves our project change listener to AsyncBatchingWorkQueue to improve stability dotnet/razor#10475 rearchitects our project syncing. Expected to have no impact on VS Code
In Linux + VS Code when creating a new project we're seeing work get dropped from the queue that would result in up to date information being written to disk. Looking at the logs + the bin file it's noticeable that the correct project information isn't there, and that results in Razor behaving poorly by not having the correct files in the correct projects, and often times lacking the accurate amount of taghelpers.
Switching to AsyncBatchingWorkQueue seems to improve reliability here. I also added more trace logging to help identify when information is being written, when files are moving, etc. A try/catch was added to make sure we log in case of an exception as well.
There are still issues on Linux, but this solves part of them.