-
-
Notifications
You must be signed in to change notification settings - Fork 210
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
fix: don't block UI when canceling lint process #688
base: master
Are you sure you want to change the base?
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.
The entries in the running_procs_by_buf
table get replaced after a :cancel
call, so I think the VimLeavePre
logic wouldn't work like this because the table won't contain the cancelled LintProcs anymore.
But the bigger problem is that if the cancel is deferred, you end up running multiple linters in parallel and you might get results updated/replaced differently.
Not sure how to deal with this. Maybe other options could be:
- Wrap your misbehaving linter in a small script that forwards sigint as sigkill
try_lint
could have a difference debounce mode, where instead of cancelling a proc, it lets it finish instead of starting a new process. Although this means the results would be stale- New lint process gets chained onto the previous lint process, so it only starts once the previous one got cancelled - but this is probably more complex than I'd like.
- Allow to define per linter what signal to use - to allow killing it immediately without sigint. Or a custom
cancel
function per linter.
That should be fine, right? Because we only need to cancel the currently running tasks on exit. Unless you're worried about the case of
If that's what you're concerned about, I can fix it pretty easily by just having another way to keep track of all active LintProcs. LMK if this is what you were thinking of or if I'm misinterpreting.
I don't think this can happen because when a LintProc is cancelled it won't publish the (now stale) diagnostics. Lines 242 to 244 in ab83154
|
Hm, then I wonder if it is needed at all as part of this PR. They weren't getting cancelled before
Good point |
If we want to scope the PR to just fixing the UI freeze, then we could leave out the |
I've been getting mysterious nondeterministic freezes in Neovim for months now, but couldn't get a solid repro. I finally found a repro and tracked it down to
LintProc:cancel()
. In #522 we added some logic to cancel a process by killing it withsigint
, waiting, then if it's still running kill it again withsigkill
. The problem is that the delay is done withvim.wait()
, which will block the UI thread. If you have a poorly-behaved linter (and I do, unfortunately it's for work and not something I can reasonably fix) that doesn't respond at all tosigint
, the UI thread will be blocked for 10 seconds each time it fails to cancel.I've replaced the synchronous
vim.wait
with a call tovim.defer_fn
. From comments on the previous PR I gather that there is some concern about orphaned lint processes when Neovim exits. There's not much we can do if it crashes, but for normal operation I added aVimLeavePre
hook that will cancel all running linters and block until they are killed.Test Plan
First I found a repro without this patch
lint.try_lint()
twiceThen after applying this patch
lint.try_lint()
twiceps aux | grep <formatter>
and verify that there are two processes runningAnd to check the exit behavior
lint.try_lint()
:q
ps aux | grep <formatter>
and verify that the formatter is runningps aux | grep <formatter>
shows that the formatter process has been killed