Repository navigation
fix: exit shortly after shutdown so clients can stop the server - #33
jamietanna wants to merge 1 commit into
Conversation
I've noticed recently that when calling `:lsp stop vale_ls` in Neovim, the `vale-ls` process remained alive. With some investigation from Claude Sonnet 5.5, it highlighted that `tower-lsp` 0.19's `Server::serve` doesn't return on `exit`. It only marks the service as exited, and the final `join!` waits on channels whose senders live outside the read loop, so it only completes once stdin reaches EOF. This also means anything placed after `serve()` in `main` is never reached. As clients like Neovim send `shutdown` then `exit`, and keep stdin open until the process exits, neither LSP client nor LSP server can proceed. In particular for Neovim, this means that `on_exit` and `LspDetach` never fire. As `exit` is the only valid message after `shutdown`, we can instead exit the process from the `shutdown` handler, after a short delay so the reply has been written. Now, we exit with exit code 0 ~0.2s after `shutdown` with stdin still open, with or without a following `exit`. We use 200ms as a guesstimate of a reasonable time to wait for a response ot be flushed. A client that was extremely slow to read could see the process exit before the reply, which should be treated as a normal shutdown. Co-Authored-By: Claude Sonnet 5.5 <claude-code@jamietanna.co.uk>
tower-lsp's `serve` only returns once stdin closes, so a client that sends `shutdown` and `exit` but keeps stdin open, as Neovim does, waited on a server that never quit. A wrapper around the service exits on `exit`: 0 after a shutdown, 1 without one, as the spec asks. Reported in #33. Signed-off-by: Joseph Kato <joseph@jdkato.io>
|
Thanks for tracking this down, and for the clear write-up of why I went with a slightly different approach in : instead of exiting from Closing this in favor of that commit. |
|
Amazing, thank you! I'd wondered about raising an issue instead - but appreciate a fix either way |
I've noticed recently that when calling
:lsp stop vale_lsin Neovim,the
vale-lsprocess remained alive.With some investigation from Claude Sonnet 5.5, it highlighted that
tower-lsp0.19'sServer::servedoesn't return onexit. It onlymarks the service as exited, and the final
join!waits on channelswhose senders live outside the read loop, so it only completes once
stdin reaches EOF.
This also means anything placed after
serve()inmainis neverreached.
As clients like Neovim send
shutdownthenexit, and keep stdin openuntil the process exits, neither LSP client nor LSP server can proceed.
In particular for Neovim, this means that
on_exitandLspDetachnever fire.
As
exitis the only valid message aftershutdown, we can insteadexit the process from the
shutdownhandler, after a short delay so thereply has been written.
Now, we exit with exit code 0 ~0.2s after
shutdownwith stdin stillopen, with or without a following
exit.We use 200ms as a guesstimate of a reasonable time to wait for a
response ot be flushed.
A client that was extremely slow to read could see the process exit
before the reply, which should be treated as a normal shutdown.
Co-Authored-By: Claude Sonnet 5.5 claude-code@jamietanna.co.uk