emacs-ycmd icon indicating copy to clipboard operation
emacs-ycmd copied to clipboard

emacs-ycmd doens't shut-down ycmd correctly

Open r4nt opened this issue 10 years ago • 36 comments

The /tmp/ycm_temp/ directory fills up with temp dirs when starting and exiting emacs. If ycm is shut down graciously (by sending sigterm or sigint) it will delete the directory.

@Valloric

r4nt avatar Jun 25 '15 20:06 r4nt

@r4nt and I encountered this behavior with an emacs user that frequently starts and exits emacs. Their ycm_temp dir ends up gigabytes big because it seems that ycmd always goes through dirty shutdown.

SIGTERM or SIGINT is what the server is supposed to receive to perform clean shutdown.

Valloric avatar Jun 25 '15 20:06 Valloric

When is the temp directory created? When I start ycmd in Emacs there is no /tmp/ycm_temp dir on my system? I saw that the cs_completer uses tempfile path in one function but I haven't used this completer yet.

ptrv avatar Jun 25 '15 23:06 ptrv

This should be fixed with the patch by @ptrv.

@r4nt Can you verify that this is ok now?

abingham avatar Jun 26 '15 08:06 abingham

@ptrv That's a bit murky. By default, ycmd will create that tempdir if the C# completer uses it... but depending on the contents of the user's ycm_extra_conf.py, it might be used there too. That's actually what we do at Google with the Google-wide ycm_extra_conf.py that almost all Google YCM users use.

Any way, other parts of ycmd also rely on clean shutdown from SIGINT/SIGTERM, this is just one atexit handler. The extra conf file (and the various semantic completers too) can have a Shutdown method that ycmd will call on clean shutdown etc.

Valloric avatar Jun 27 '15 04:06 Valloric

It looks like the referenced fix was rolled back? Can we perhaps implement a shutdown command in ycmd that can be sent via the rpc interface?

r4nt avatar Mar 13 '16 08:03 r4nt

@r4nt The roll back has been fixed again with 00fa90b55e420be7095a2ed1a16aa50d0a2029b3. We use interrupt-process which sends an SIGINT to the server.

ptrv avatar Mar 13 '16 12:03 ptrv

@ptrv Is it time to merge in your PR for using the new shutdown API?

abingham avatar Mar 14 '16 08:03 abingham

@abingham The upstream PR is still not merged, so we'll still have to wait.

ptrv avatar Mar 14 '16 09:03 ptrv

So, I still have users reporting huge /tmp residues. I'm wondering whether we hit the timeout after interrupt-process...

r4nt avatar Mar 14 '16 11:03 r4nt

I'm wondering whether we hit the timeout after interrupt-process... Do you mean, is it possible that interrupt-process is somehow preventing the ycmd server from doing idle suicide? I suppose that's possible, but I suppose we'd need to really dig into what all is happening.

My first guess would be that we're not giving ycmd enough time to clean up after calling interrupt in some cases. When we call interrupt-process, we also optionally wait some amount of time and then call delete-process. In particular, ycmd-open calls ycmd-close with a hard-coded timeout of 0.5 seconds, this timeout being the amount of time we'll wait between the interrupt- and delete-process calls...perhaps this isn't long enough.

@r4nt: I can create a branch where that 0.5 seconds is configurable. Could you get one or two of your users to try it with a higher value?

abingham avatar Mar 14 '16 11:03 abingham

@ptrv I figure they're configuring their logging through ycmd-server-args, if that's what you mean.

abingham avatar Mar 14 '16 11:03 abingham

We also have the option keep_logfiles by default. Isn't that causing the logfiles not being deleted?

ptrv avatar Mar 14 '16 11:03 ptrv

Good catch...that's probably not helping! We should make that configurable, I think. Do you know if the command-line argument --keep_logfile overrides the setting in ycmd--options-contents? (I'm not able to really test anything out in my current work environment...)

abingham avatar Mar 14 '16 12:03 abingham

@r4nt I've created a branch that lets you specify the delete-process delay for ycmd-open. You can test it out of you want; just customize the ycmd-open-delete-process-delay setting.

My guess, however, is that @ptrv is onto something more relevant, i.e. that we explicitly tell ycmd to keep its logfiles, both through the options file and command-line arguments. More on that soon, I think...

abingham avatar Mar 14 '16 12:03 abingham

Note that in our case the problem is not log files - we have a ycm_extra_config for our site that copies the right version of libclang into YCM's /tmp directory.

r4nt avatar Mar 14 '16 14:03 r4nt

In that case I think the branch I mentioned earlier might be the thing to try. Assuming that the problem is us not giving ycmd sufficient time (0.5 seconds) to shut down, that branch should let you try different timeouts.

abingham avatar Mar 14 '16 14:03 abingham

Should just using eval-buffer on ycm.el downloaded form the branch (after I loaded a different version) and setting the timeout work? Because exiting via C-x-c still instant-exits without any cleanups.

r4nt avatar Mar 15 '16 11:03 r4nt

The thing is, that the timeout is only applied when you restart the server from within emacs, i.e. when you close and quickly after that you start the server. Only in that case we need to wait for the server to finish. With calling ycmd-close there is only an interrupt-process call.

On closing emacs the ycmd-close function is called from kill-emacs-hook without any timeout and therefore only with interrupt-process.

@r4nt Is there any cleanup when you stop the server by calling ycmd-close without existing Emacs? If not, the problem might be something else then just the timeout.

ptrv avatar Mar 15 '16 11:03 ptrv

Also I only saw code in ycmd to remove the logfiles on SIGTERM or SIGINT. Can someone give me a hint where the code is to remove ycm_temp?

Here https://github.com/Valloric/ycmd/blob/master/ycmd/main.py#L59-L80 only logfiles are deleted.

ptrv avatar Mar 15 '16 11:03 ptrv

Yep, if I call ycmd-close without exiting, cleanup is happening.

r4nt avatar Mar 15 '16 13:03 r4nt

Ok, then we need to investigate why the cleanup is not happening when ycmd-close is called with kill-emacs-hook

ptrv avatar Mar 15 '16 14:03 ptrv

I removed the --keep_logfiles flag from the server command and the cleanup of logfiles worked just fine when exiting Emacs.

@r4nt Can you provide some reproduction steps for the issue or the global config which copies over files to the temp folder? Otherwise I don't know how to debug and track down the issue.

ptrv avatar Mar 15 '16 15:03 ptrv

Note that the cleanup @r4nt is talking about is related to the custom cleanup function that the user can register through ycm_extra_conf.py. If the extra conf file has a Shutdown() function, ycmd calls it when shutting down. If there's a YcmCorePreload() function, it's called on ycmd startup.

Valloric avatar Mar 15 '16 17:03 Valloric

@Valloric Thanks for the hint. I haven't use Shutdown() or YcmCorePreload() function yet. Will check them with emacs shutdown.

ptrv avatar Mar 15 '16 17:03 ptrv

So, should the timeout be active on shutdown? (that is, could it be a timeout issue due to ycmd taking too long to shut down, and the kill then happening while it's still trying to clean up? or is that a red herring?)

r4nt avatar Mar 15 '16 19:03 r4nt

Ok, the problem is that we use start-process to run the ycmd process asynchronously but when exiting Emacs the ycmd child process gets killed. We added ycmd-close to kill-emacs-hook but Emacs does not wait for ycmd to shut down.

I guess we need to have the process to stay alive even after Emacs gets killed. With start-process this does not work. There is the command (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) to start a process and passing 0 for BUFFER starts a process without waiting to finish, but this does not return the process object and we have no server buffer with this.

It would need a refactoring of the process handling to be able to use the call-process instead of start-process command.

ptrv avatar Mar 16 '16 00:03 ptrv

Could this be related to a bug in emacs?

And also, could we use process sentinels to ensure that the process has completely exited when we're shutting down?

abingham avatar Mar 16 '16 08:03 abingham

@abingham I tried the example from the bug report bug report and added (setq kill-emacs-hook '((lambda () (sit-for 4)))) and I terminated emacs and Emacs waited the 4 seconds before it quit.

So maybe it is enough to call ycmd-close with a timeout in the kill-emacs-hook.

Also we could try to use a sentinel and the wait until the process notifies us that it is terminated.

ptrv avatar Mar 16 '16 09:03 ptrv

It seems like we'll need a timeout no matter how we approach it. That is, we have to be prepared for the possibility that the server doesn't die for whatever reason. A sentinel doesn't seem to provide any improved functionality over the simple timeout you mentioned, so I think we should try the timeout first.

abingham avatar Mar 16 '16 10:03 abingham

I'll look into it

ptrv avatar Mar 16 '16 10:03 ptrv