Skip to content
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] Prevent simultaneous starts of OmniSharp server #310

Merged
merged 6 commits into from
Jan 18, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 40 additions & 50 deletions ycmd/completers/cs/cs_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,17 +201,17 @@ def GetSubcommandsMap( self ):
'GetDoc' : ( lambda self, request_data, args:
self._SolutionSubcommand( request_data,
method = '_GetDoc' ) ),
'ServerRunning' : ( lambda self, request_data, args:
'ServerIsRunning' : ( lambda self, request_data, args:
self._SolutionSubcommand( request_data,
method = 'ServerIsRunning',
no_request_data = True ) ),
'ServerReady' : ( lambda self, request_data, args:
'ServerIsHealthy' : ( lambda self, request_data, args:
self._SolutionSubcommand( request_data,
method = 'ServerIsReady',
method = 'ServerIsHealthy',
no_request_data = True ) ),
'ServerTerminated' : ( lambda self, request_data, args:
'ServerIsReady' : ( lambda self, request_data, args:
self._SolutionSubcommand( request_data,
method = 'ServerTerminated',
method = 'ServerIsReady',
no_request_data = True ) )
}

Expand All @@ -227,11 +227,18 @@ def _SolutionSubcommand( self, request_data, method,
def OnFileReadyToParse( self, request_data ):
solutioncompleter = self._GetSolutionCompleter( request_data )

if ( not solutioncompleter.ServerIsRunning() and
self.user_options[ 'auto_start_csharp_server' ] ):
# Only start the server associated to this solution if the option to
# automatically start one is set and no server process is already running.
if ( self.user_options[ 'auto_start_csharp_server' ]
and not solutioncompleter.ServerIsRunning() ):
solutioncompleter._StartServer()
return

# Bail out if the server is unresponsive. We don't start or restart the
# server in this case because current one may still be warming up.
if not solutioncompleter.ServerIsHealthy():
return

errors = solutioncompleter.CodeCheck( request_data )

diagnostics = [ self._QuickFixToDiagnostic( x ) for x in
Expand Down Expand Up @@ -293,32 +300,20 @@ def DebugInfo( self, request_data ):
return 'OmniSharp Server is not running'


def ServerIsRunning( self, request_data = None ):
""" Check if our OmniSharp server is running. """
return self._CheckSingleOrAllActive( request_data,
lambda i: i.ServerIsRunning() )
def ServerIsHealthy( self ):
""" Check if our OmniSharp server is healthy (up and serving). """
return self._CheckAllRunning( lambda i: i.ServerIsHealthy() )


def ServerIsReady( self, request_data = None ):
def ServerIsReady( self ):
""" Check if our OmniSharp server is ready (loaded solution file)."""
return self._CheckSingleOrAllActive( request_data,
lambda i: i.ServerIsReady() )
return self._CheckAllRunning( lambda i: i.ServerIsReady() )


def ServerTerminated( self, request_data = None ):
""" Check if the server process has already terminated. """
return self._CheckSingleOrAllActive( request_data,
lambda i: i.ServerTerminated() )


def _CheckSingleOrAllActive( self, request_data, action ):
if request_data is not None:
solutioncompleter = self._GetSolutionCompleter( request_data )
return action( solutioncompleter )
else:
solutioncompleters = self._completer_per_solution.values()
return all( action( completer )
for completer in solutioncompleters if completer.ServerIsActive() )
def _CheckAllRunning( self, action ):
solutioncompleters = self._completer_per_solution.values()
return all( action( completer ) for completer in solutioncompleters
if completer.ServerIsRunning() )


def _GetSolutionFile( self, filepath ):
Expand Down Expand Up @@ -402,7 +397,7 @@ def _StopServer( self ):
self._TryToStopServer()

# Kill it if it's still up
if not self.ServerTerminated() and self._omnisharp_phandle is not None:
if self.ServerIsRunning():
self._logger.info( 'Killing OmniSharp server' )
self._omnisharp_phandle.kill()

Expand All @@ -418,7 +413,7 @@ def _TryToStopServer( self ):
except:
pass
for _ in range( 10 ):
if self.ServerTerminated():
if not self.ServerIsRunning():
return
time.sleep( .1 )

Expand Down Expand Up @@ -546,36 +541,31 @@ def _DefaultParameters( self, request_data ):
return parameters


def ServerIsActive( self ):
""" Check if our OmniSharp server is active (started, not yet stopped)."""
try:
return bool( self._omnisharp_port )
except:
return False
def ServerIsRunning( self ):
""" Check if our OmniSharp server is running (process is up)."""
return utils.ProcessIsRunning( self._omnisharp_phandle )


def ServerIsRunning( self ):
""" Check if our OmniSharp server is running (up and serving)."""
def ServerIsHealthy( self ):
""" Check if our OmniSharp server is healthy (up and serving)."""
if not self.ServerIsRunning():
return False

try:
return bool( self._omnisharp_port and
self._GetResponse( '/checkalivestatus', timeout = .2 ) )
except:
return self._GetResponse( '/checkalivestatus', timeout = .2 )
except requests.exceptions.RequestException:
return False


def ServerIsReady( self ):
""" Check if our OmniSharp server is ready (loaded solution file)."""
try:
return bool( self._omnisharp_port and
self._GetResponse( '/checkreadystatus', timeout = .2 ) )
except:
if not self.ServerIsRunning():
return False


def ServerTerminated( self ):
""" Check if the server process has already terminated. """
return ( self._omnisharp_phandle is not None and
self._omnisharp_phandle.poll() is not None )
try:
return self._GetResponse( '/checkreadystatus', timeout = .2 )
except requests.exceptions.RequestException:
return False


def _SolutionFile( self ):
Expand Down
3 changes: 1 addition & 2 deletions ycmd/completers/javascript/tern_completer.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,7 @@ def _StopServerNoLock( self ):


def _ServerIsRunning( self ):
return ( self._server_handle is not None and
self._server_handle.poll() is None )
return utils.ProcessIsRunning( self._server_handle )


def _GetType( self, request_data ):
Expand Down
2 changes: 1 addition & 1 deletion ycmd/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def GetHealthy():
_logger.info( 'Received health request' )
if request.query.include_subservers:
cs_completer = _server_state.GetFiletypeCompleter( ['cs'] )
return _JsonResponse( cs_completer.ServerIsRunning() )
return _JsonResponse( cs_completer.ServerIsHealthy() )
return _JsonResponse( True )


Expand Down
4 changes: 2 additions & 2 deletions ycmd/tests/cs/cs_handlers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ def _WaitUntilOmniSharpServerReady( self, filename ):
success = True
break
request = self._BuildRequest( completer_target = 'filetype_default',
command_arguments = [ 'ServerTerminated' ],
command_arguments = [ 'ServerIsRunning' ],
filepath = filename,
filetype = 'cs' )
result = self._app.post_json( '/run_completer_command', request ).json
if result:
if not result:
raise RuntimeError( "OmniSharp failed during startup." )
time.sleep( 0.2 )
retries = retries - 1
Expand Down
4 changes: 4 additions & 0 deletions ycmd/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ def OnTravis():
return 'TRAVIS' in os.environ


def ProcessIsRunning( handle ):
return handle is not None and handle.poll() is None


# From here: http://stackoverflow.com/a/8536476/1672783
def TerminateProcess( pid ):
if OnWindows():
Expand Down