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
[READY] Properly shut down on Windows #282
Conversation
f531a2b
to
827cf79
Compare
This is important work; thanks for taking it on! I didn't know we left sub-servers running after ycmd exits on Windows. That's a pretty bad bug. |
This PR is really awesome and needed! 👍 Is also pretty straightforward to understand since @micbou explained well what was needed. Anyhow I left a comment on a file since I don't understand why the sleep is needed, and if is needed how do we know that Reviewed 9 of 10 files at r1. ycmd/handlers.py, line 269 [r1] (raw file): Comments from the review on Reviewable.io |
AppVeyor failures are not related to this PR. See PR #283.
I think this is better to refactor now than later. I already did some refactoring by reusing functions from the Review status: 9 of 10 files reviewed at latest revision, 1 unresolved discussion, some commit checks failed. ycmd/handlers.py, line 269 [r1] (raw file): Comments from the review on Reviewable.io |
Before this will land into master we should ping @abingham (emacs-ycmd), @Qusic (atom-youcompleteme), @mawww (kak-ycmd) since this will change how to shutdown the ycmd server. Review status: 9 of 10 files reviewed at latest revision, 1 unresolved discussion, some commit checks failed. Comments from the review on Reviewable.io |
Another thing to consider refactoring is the class which performs full integration tests. A large part of the class in Would potentially also allow more separation, such as testing Tern completer's "shutdown" method within the That might also give us a canonical minimal ycmd client, which could be useful or educational in its own right. Reviewed 10 of 10 files at r1. examples/example_client.py, line 110 [r1] (raw file): if self.IsAlive():
# the server didn't terminate for some reason. kill it.
self._popen_handle.terminate() it looks like travis/travis_install.sh, line 39 [r1] (raw file): echo -e "..." > \
${YCMD_VENV_DIR}/.... I think that works... ycmd/main.py, line 94 [r1] (raw file): ycmd/main.py, line 155 [r1] (raw file): ycmd/handlers.py, line 219 [r1] (raw file): ycmd/handlers.py, line 269 [r1] (raw file): I feel we should either try to synchronise it (I'm not sure how), or just exit synchronously and state in the API that no response is received to a shutdown request and the communication session is terminated (TCP reset). I'm guessing that you probably tried this and had some sort of problem with the client and/or tests? ycmd/tests/server_test.py, line 180 [r1] (raw file): Could we use
ycmd/watchdog_plugin.py, line 45 [r1] (raw file): Do we document the ycmd options anywhere else, like in the README.md ? Comments from the review on Reviewable.io |
827cf79
to
a4aaf80
Compare
Review status: 5 of 10 files reviewed at latest revision, 8 unresolved discussions. ycmd/watchdog_plugin.py, line 45 [r1] (raw file): The description is in the watchdog plugin https://github.com/Valloric/ycmd/blob/8d6cf88518a4cbd90d242abbf13d25b39fee1552/ycmd/watchdog_plugin.py#L29 Comments from the review on Reviewable.io |
Reviewed 5 of 5 files at r2. Comments from the review on Reviewable.io |
Review status: all files reviewed at latest revision, 7 unresolved discussions. examples/example_client.py, line 110 [r1] (raw file): travis/travis_install.sh, line 39 [r1] (raw file): ycmd/main.py, line 155 [r1] (raw file): ycmd/handlers.py, line 219 [r1] (raw file): ycmd/handlers.py, line 269 [r1] (raw file): ycmd/tests/server_test.py, line 180 [r1] (raw file): Comments from the review on Reviewable.io |
ycmd/handlers.py, line 219 [r1] (raw file): Comments from the review on Reviewable.io |
Reviewed 4 of 5 files at r2. ycmd/handlers.py, line 269 [r1] (raw file): ycmd/tests/server_test.py, line 93 [r2] (raw file): Comments from the review on Reviewable.io |
Review status: all files reviewed at latest revision, 3 unresolved discussions. ycmd/main.py, line 94 [r1] (raw file): Comments from the review on Reviewable.io |
Review status: all files reviewed at latest revision, 3 unresolved discussions. ycmd/main.py, line 94 [r1] (raw file): Comments from the review on Reviewable.io |
Does the SIGTERM signal still works correctly ? or do we need to go through the shutdown command now ? kak-ycmd is not expected to run directly on windows, but always on cygwin, so I assume SIGTERM will still work there, which means its it not urgent to tweak kak-ycmd to support the shutdown command if SIGTERM is still a supported way to close ycmd. |
Thanks for looping me in on this. It sounds like the only substantial change from the client point of view is that we'll call |
I moved the infrastructure to a new class
In PR current state, you can still use the SIGTERM signal to stop the server and it should stay that way. Our goal is to provide a portable (and therefore recommended) way to shutdown the server. Review status: 9 of 11 files reviewed at latest revision, 3 unresolved discussions. ycmd/handlers.py, line 269 [r1] (raw file):
Comments from the review on Reviewable.io |
The ycmd server has now a shutdown handler and we need to send a shutdown request instead of killing the process. See ycm-core/ycmd#282 Resolves abingham#240
Reviewed 3 of 3 files at r4. ycmd/handlers.py, line 269 [r1] (raw file): Comments from the review on Reviewable.io |
Review status: all files reviewed at latest revision, 2 unresolved discussions. ycmd/handlers.py, line 269 [r1] (raw file): Comments from the review on Reviewable.io |
Review status: all files reviewed at latest revision, 2 unresolved discussions. ycmd/handlers.py, line 269 [r1] (raw file):
Just a matter of a Comments from the review on Reviewable.io |
Review status: all files reviewed at latest revision, 2 unresolved discussions. ycmd/handlers.py, line 269 [r1] (raw file):
Comments from the review on Reviewable.io |
Review status: all files reviewed at latest revision, 2 unresolved discussions. ycmd/handlers.py, line 269 [r1] (raw file): If we were ever decide to lock ourselves into a particular server framework, it's going to be for a very good reason. This case doesn't strike me as that. Not returning from a Comments from the review on Reviewable.io |
The ycmd server has now a shutdown handler and we need to send a shutdown request instead of killing the process. See ycm-core/ycmd#282 Resolves abingham#240
The ycmd server has now a shutdown handler and we need to send a shutdown request instead of killing the process. See ycm-core/ycmd#282 Resolves abingham#240
☔ The latest upstream changes (presumably #296) made this pull request unmergeable. Please resolve the merge conflicts. |
7e9177f
to
7016b88
Compare
@micbou is something still missing? Can we call |
Test if server and subservers are properly shut down from a handler or the watchdog plugin. By using a handler, we have a portable way to properly shut down the server from a client.
By switching from the low-level Python thread module to the threading module in 0.8.10, Waitress is now correctly traced by coverage.py. Since some of our tests are using Waitress to start a WSGI app, we are updating it to fix this coverage issue.
Rebased and squashed. This is ready now. Reviewed 1 of 1 files at r19, 1 of 1 files at r20. Comments from Reviewable |
Awesome, let's go! @homu r=puremourning |
📌 Commit ed23b23 has been approved by |
⚡ Test exempted - status |
[READY] Properly shut down on Windows ### Problem When killing a process on Windows, it is terminated like it received a `SIGKILL` signal on Linux. This means that @atexit functions will not be called. In our case, `ServerCleanup` is not executed: completers `Shutdown` methods are not called, neither the `Shutdown` function in the global extra conf. In particular, subservers like `OmniSharpServer` and `Tern.js` are left running. This issue happens in two situations: - [a client like YCM terminates the ycmd server](https://github.com/Valloric/YouCompleteMe/blob/master/python/ycm/youcompleteme.py#L175); - [watchdog plugin pulls the trigger](https://github.com/Valloric/ycmd/blob/master/ycmd/watchdog_plugin.py#L92). How to solve it? ### Solution First situation should be solved by adding a new handler `/shutdown` to properly shut down the ycmd server from a client. Unfortunately, `waitress` and `bottle` don't provide an easy way to shut it down. Using `sys.exit()` in the `/shutdown` handler will not work because it is run in a thread. The solution is to use the same mechanism as in the watchdog plugin. After cleaning up, we start a thread to immediately kill the server. Second situation is fixed by using the function associated to the `/shutdown` handler in the watchdog plugin. ### Tests To test that the shutdown handler and the watchdog plugin are properly working, we need to start the ycmd server for real. We cannot use [webtest](https://webtest.readthedocs.org/en/latest/) here. I added 4 tests, which are a combination of shutting down ycmd without and with a subserver, from a request and from the watchdog plugin. [psutil](http://pythonhosted.org/psutil/) module was added to the test requirements to work with processes in a portable way. In order to test the watchdog plugin, I added a command-line argument to set the `check_interval_seconds` variable. Since we are starting subprocesses in those tests, some changes were needed to enable coverage in Python subprocesses. Another change to improve coverage was to update Waitress to version 0.8.10. See the commit message for some explanation. A benefit of those tests is a significant increase in coverage (~6%). ### Caveats - Tests may introduce flakyness. Robustness should be improved; - Coverage seems to cause issue with the Gocode daemon. Not sure if it is related to this PR. Need to investigate. ### Next - Update YCM to use the `shutdown` handler (fix issue ycm-core/YouCompleteMe#876); - Fix logfiles clean up on Windows. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/valloric/ycmd/282) <!-- Reviewable:end -->
[READY] Implement shutdown handler This PR depends on ycm-core/ycmd#282. We don't want to block Vim exit if the server takes too much time to answer the shutdown request so we use a timeout of 100ms for this request. In my experience, it takes ~5ms. The `YcmStopServer` command only exists for testing purpose. It will be removed in the final version of this PR. Fixes #876. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/youcompleteme/2245) <!-- Reviewable:end -->
The server startup behavior changed also a bit, didn't it? After start there is no print |
@ptrv does that mean this commit breaks emacs-ycmd ? How is the ycmd version tied to emacs-ycmd? I seem to recall that some folk install it independently? If so then I think we may have a problem that we need to fix. |
Yes this commit breaks emacs-ycmd. Unfortunately we do not tie a specific ycmd version to it. Probably we should, but that's different story. The quick fix in |
The difference is because we are no longer calling |
That would help a lot for now. and then emacs-ycmd needs to implement a way to tie the server version. |
[READY] Print a message equivalent to that printed by waitress.serve #282 breaks emacs-ycmd as it parses the standard output to get the port that ycmd is listening on. While it probably makes sense for emacs-ycmd to specify the port, this is a regression so we re-introduce the output equivalent to [`waitress.serve`](https://github.com/Pylons/waitress/blob/3850e4c09aa9a55dc5c61985981b4ef719d5ebb8/waitress/__init__.py#L13-L14) <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/valloric/ycmd/555) <!-- Reviewable:end -->
@ptrv any chance you could kick the tyres on the latest commit ? I don't have an emacs at hand... |
@puremourning The patch works. Thanks! |
Cool. I did try and make an emacs that worked with ycmd, but i'm too much of an emacs noob to make it work. i tried spacemacs and, well, none of the ycmd- commands seems to do anything. So thanks for checking, i'll stick to vim ^_^ |
[READY] Add shutdown handler Adding a `shutdown` endpoint makes it possible to cleanly exit JediHTTP on Windows. This is implemented the same way as in ycmd. See PR ycm-core/ycmd#282 for more detail. I made the following changes to the setup and teardown methods of the end-to-end tests: - start the server with logging level set to `debug`; - wait for the server to be ready before each test; - use the new `shutdown` handler to stop the server after each test; - write the output of the server to nosetests stdout at the end of each test. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/vheon/jedihttp/39) <!-- Reviewable:end -->
Problem
When killing a process on Windows, it is terminated like it received a
SIGKILL
signal on Linux. This means that @atexit functions will not be called. In our case,ServerCleanup
is not executed:completers
Shutdown
methods are not called, neither theShutdown
function in the global extra conf. In particular, subservers likeOmniSharpServer
andTern.js
are left running.This issue happens in two situations:
How to solve it?
Solution
First situation should be solved by adding a new handler
/shutdown
to properly shut down the ycmd server from a client. Unfortunately,waitress
andbottle
don't provide an easy way to shut it down. Usingsys.exit()
in the/shutdown
handler will not work because it is run in a thread. The solution is to use the same mechanism as in the watchdog plugin. After cleaning up, we start a thread to immediately kill the server.Second situation is fixed by using the function associated to the
/shutdown
handler in the watchdog plugin.Tests
To test that the shutdown handler and the watchdog plugin are properly working, we need to start the ycmd server for real. We cannot use webtest here. I added 4 tests, which are a combination of shutting down ycmd without and with a subserver, from a request and from the watchdog plugin.
psutil module was added to the test requirements to work with processes in a portable way.
In order to test the watchdog plugin, I added a command-line argument to set the
check_interval_seconds
variable.Since we are starting subprocesses in those tests, some changes were needed to enable coverage in Python subprocesses. Another change to improve coverage was to update Waitress to version 0.8.10. See the commit message for some explanation.
A benefit of those tests is a significant increase in coverage (~6%).
Caveats
Next
shutdown
handler (fix issue Omnisharp server is not stopped on Gvim exit YouCompleteMe#876);