Cleaner server shutdown

Listening for VimLeave was sub-optimal. popen.terminate() is much cleaner.
This commit is contained in:
Strahinja Val Markovic 2013-09-23 14:33:14 -07:00
parent f51a687297
commit 088eb4d0d2
7 changed files with 44 additions and 44 deletions

View File

@ -109,7 +109,10 @@ class Completer( object ):
configuration. configuration.
When the command is called with no arguments you should print a short summary When the command is called with no arguments you should print a short summary
of the supported commands or point the user to the help section where this of the supported commands or point the user to the help section where this
information can be found.""" information can be found.
Override the Shutdown() member function if your Completer subclass needs to do
custom cleanup logic on server shutdown."""
__metaclass__ = abc.ABCMeta __metaclass__ = abc.ABCMeta
@ -277,10 +280,6 @@ class Completer( object ):
pass pass
def OnVimLeave( self, request_data ):
pass
def OnUserCommand( self, arguments, request_data ): def OnUserCommand( self, arguments, request_data ):
raise NotImplementedError( NO_USER_COMMANDS ) raise NotImplementedError( NO_USER_COMMANDS )
@ -324,6 +323,10 @@ class Completer( object ):
return '' return ''
def Shutdown( self ):
pass
class CompletionsCache( object ): class CompletionsCache( object ):
def __init__( self ): def __init__( self ):
self.line = -1 self.line = -1

View File

@ -46,11 +46,11 @@ class CsharpCompleter( ThreadedCompleter ):
self._omnisharp_port = None self._omnisharp_port = None
self._logger = logging.getLogger( __name__ ) self._logger = logging.getLogger( __name__ )
# if self.user_options[ 'auto_start_csharp_server' ]: if self.user_options[ 'auto_start_csharp_server' ]:
# self._StartServer() self._StartServer()
def OnVimLeave( self ): def Shutdown( self ):
if ( self.user_options[ 'auto_start_csharp_server' ] and if ( self.user_options[ 'auto_start_csharp_server' ] and
self._ServerIsRunning() ): self._ServerIsRunning() ):
self._StopServer() self._StopServer()

View File

@ -115,11 +115,6 @@ class GeneralCompleterStore( Completer ):
completer.OnInsertLeave( request_data ) completer.OnInsertLeave( request_data )
def OnVimLeave( self, request_data ):
for completer in self._all_completers:
completer.OnVimLeave( request_data )
def OnCurrentIdentifierFinished( self, request_data ): def OnCurrentIdentifierFinished( self, request_data ):
for completer in self._all_completers: for completer in self._all_completers:
completer.OnCurrentIdentifierFinished( request_data ) completer.OnCurrentIdentifierFinished( request_data )
@ -128,3 +123,10 @@ class GeneralCompleterStore( Completer ):
def GettingCompletions( self ): def GettingCompletions( self ):
for completer in self._all_completers: for completer in self._all_completers:
completer.GettingCompletions() completer.GettingCompletions()
def Shutdown( self ):
for completer in self._all_completers:
completer.Shutdown()

View File

@ -65,8 +65,11 @@ def CallExtraConfYcmCorePreloadIfExists():
_CallExtraConfMethod( 'YcmCorePreload' ) _CallExtraConfMethod( 'YcmCorePreload' )
def OnVimLeave( request_data ): def Shutdown():
# VimClose is for the sake of backwards compatibility; it's a no-op when it
# doesn't exist.
_CallExtraConfMethod( 'VimClose' ) _CallExtraConfMethod( 'VimClose' )
_CallExtraConfMethod( 'Shutdown' )
def _CallExtraConfMethod( function_name ): def _CallExtraConfMethod( function_name ):

View File

@ -19,7 +19,7 @@
import sys import sys
import os import os
import threading import atexit
# We want to have the YouCompleteMe/python directory on the Python PATH because # We want to have the YouCompleteMe/python directory on the Python PATH because
# all the code already assumes that it's there. This is a relic from before the # all the code already assumes that it's there. This is a relic from before the
@ -37,9 +37,7 @@ import json
import bottle import bottle
from bottle import run, request, response from bottle import run, request, response
import server_state import server_state
from ycm import extra_conf_store
from ycm import user_options_store from ycm import user_options_store
from ycm import utils
import argparse import argparse
# num bytes for the request body buffer; request.json only works if the request # num bytes for the request body buffer; request.json only works if the request
@ -68,16 +66,6 @@ def EventNotification():
getattr( SERVER_STATE.GetFiletypeCompleter( filetypes ), getattr( SERVER_STATE.GetFiletypeCompleter( filetypes ),
event_handler )( request_data ) event_handler )( request_data )
try:
if hasattr( extra_conf_store, event_handler ):
getattr( extra_conf_store, event_handler )( request_data )
except OSError as e:
LOGGER.exception( e )
if event_name == 'VimLeave':
_ScheduleServerShutdown()
@app.post( '/run_completer_command' ) @app.post( '/run_completer_command' )
def RunCompleterCommand(): def RunCompleterCommand():
@ -147,17 +135,9 @@ def _JsonResponse( data ):
return json.dumps( data ) return json.dumps( data )
def _ScheduleServerShutdown(): @atexit.register
# The reason why we want to schedule a shutdown in the near future instead of def _ServerShutdown():
# just shutting down right now is because we want the current request (the one SERVER_STATE.Shutdown()
# that made us want to shutdown) to complete successfully first.
def Shutdown():
# sys.exit() doesn't work because we're not in the main thread.
utils.TerminateProcess( os.getpid() )
killer_thread = threading.Timer( 2, Shutdown )
killer_thread.start()
def Main(): def Main():

View File

@ -19,6 +19,7 @@
import imp import imp
import os import os
from ycm import extra_conf_store
from ycm.completers.general.general_completer_store import GeneralCompleterStore from ycm.completers.general.general_completer_store import GeneralCompleterStore
@ -27,6 +28,7 @@ class ServerState( object ):
self._user_options = user_options self._user_options = user_options
self._filetype_completers = {} self._filetype_completers = {}
self._gencomp = GeneralCompleterStore( self._user_options ) self._gencomp = GeneralCompleterStore( self._user_options )
extra_conf_store.CallExtraConfYcmCorePreloadIfExists()
@property @property
@ -34,6 +36,15 @@ class ServerState( object ):
return self._user_options return self._user_options
def Shutdown( self ):
for completer in self._filetype_completers.itervalues():
completer.Shutdown()
self._gencomp.Shutdown()
extra_conf_store.Shutdown()
def _GetFiletypeCompleterForFiletype( self, filetype ): def _GetFiletypeCompleterForFiletype( self, filetype ):
try: try:
return self._filetype_completers[ filetype ] return self._filetype_completers[ filetype ]

View File

@ -39,6 +39,7 @@ class YouCompleteMe( object ):
self._current_completion_request = None self._current_completion_request = None
self._server_stdout = None self._server_stdout = None
self._server_stderr = None self._server_stderr = None
self._server_popen = None
self._SetupServer() self._SetupServer()
@ -54,7 +55,7 @@ class YouCompleteMe( object ):
BaseRequest.server_location = 'http://localhost:' + str( server_port ) BaseRequest.server_location = 'http://localhost:' + str( server_port )
if self._user_options[ 'server_use_vim_stdout' ]: if self._user_options[ 'server_use_vim_stdout' ]:
subprocess.Popen( command, shell = True ) self._server_popen = subprocess.Popen( command, shell = True )
else: else:
filename_format = os.path.join( utils.PathToTempDir(), filename_format = os.path.join( utils.PathToTempDir(),
'server_{port}_{std}.log' ) 'server_{port}_{std}.log' )
@ -66,10 +67,10 @@ class YouCompleteMe( object ):
with open( self._server_stderr, 'w' ) as fstderr: with open( self._server_stderr, 'w' ) as fstderr:
with open( self._server_stdout, 'w' ) as fstdout: with open( self._server_stdout, 'w' ) as fstdout:
subprocess.Popen( command, self._server_popen = subprocess.Popen( command,
stdout = fstdout, stdout = fstdout,
stderr = fstderr, stderr = fstderr,
shell = True ) shell = True )
def CreateCompletionRequest( self ): def CreateCompletionRequest( self ):
@ -146,7 +147,7 @@ class YouCompleteMe( object ):
def OnVimLeave( self ): def OnVimLeave( self ):
SendEventNotificationAsync( 'VimLeave' ) self._server_popen.terminate()
def OnCurrentIdentifierFinished( self ): def OnCurrentIdentifierFinished( self ):