From 7248979bb4b97fd31500303c23d652ab0a8bf528 Mon Sep 17 00:00:00 2001 From: Strahinja Val Markovic Date: Wed, 2 Oct 2013 17:09:25 -0700 Subject: [PATCH] We now handle the starting FileReadyToParse event The problem was that when you start vim like "vim foo.cc", the FileReadyToParse event is sent to the server before it's actually started up. Basically, a race condition. We _really_ don't want to miss that event. For C++ files, it tells the server to start compiling the file. So now PostDataToHandlerAsync in BaseRequest will retry the request 3 times (with exponential backoff) before failing, thus giving the server time to boot. --- python/ycm/client/base_request.py | 44 ++++++++++++++++++++++--- python/ycm/client/event_notification.py | 12 +------ 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/python/ycm/client/base_request.py b/python/ycm/client/base_request.py index 4c46a5d9..d67836a5 100644 --- a/python/ycm/client/base_request.py +++ b/python/ycm/client/base_request.py @@ -20,10 +20,15 @@ import vim import json import requests +from retries import retries from requests_futures.sessions import FuturesSession +from concurrent.futures import ThreadPoolExecutor from ycm import vimsupport HEADERS = {'content-type': 'application/json'} +# TODO: This TPE might be the reason we're shutting down slowly. It seems that +# it waits for all worker threads to stop before letting the interpreter exit. +EXECUTOR = ThreadPoolExecutor( max_workers = 4 ) class ServerError( Exception ): def __init__( self, message ): @@ -57,12 +62,24 @@ class BaseRequest( object ): # This returns a future! Use JsonFromFuture to get the value. @staticmethod def PostDataToHandlerAsync( data, handler ): - return BaseRequest.session.post( _BuildUri( handler ), - data = json.dumps( data ), - headers = HEADERS ) + def PostData( data, handler ): + return BaseRequest.session.post( _BuildUri( handler ), + data = json.dumps( data ), + headers = HEADERS ) + + @retries( 3, delay = 0.5 ) + def DelayedPostData( data, handler ): + return requests.post( _BuildUri( handler ), + data = json.dumps( data ), + headers = HEADERS ) + + if not _CheckServerIsHealthyWithCache(): + return EXECUTOR.submit( DelayedPostData, data, handler ) + + return PostData( data, handler ) - session = FuturesSession( max_workers = 4 ) + session = FuturesSession( executor = EXECUTOR ) server_location = 'http://localhost:6666' @@ -102,3 +119,22 @@ def _BuildUri( handler ): return ''.join( [ BaseRequest.server_location, '/', handler ] ) +SERVER_HEALTHY = False + +def _CheckServerIsHealthyWithCache(): + global SERVER_HEALTHY + + def _ServerIsHealthy(): + response = requests.get( _BuildUri( 'healthy' ) ) + response.raise_for_status() + return response.json() + + if SERVER_HEALTHY: + return True + + try: + SERVER_HEALTHY = _ServerIsHealthy() + return SERVER_HEALTHY + except: + return False + diff --git a/python/ycm/client/event_notification.py b/python/ycm/client/event_notification.py index 62c0fa65..c39a4f43 100644 --- a/python/ycm/client/event_notification.py +++ b/python/ycm/client/event_notification.py @@ -17,8 +17,6 @@ # You should have received a copy of the GNU General Public License # along with YouCompleteMe. If not, see . -import traceback -from ycm import vimsupport from ycm.client.base_request import BaseRequest, BuildRequestData @@ -35,15 +33,7 @@ class EventNotification( BaseRequest ): request_data.update( self._extra_data ) request_data[ 'event_name' ] = self._event_name - # On occasion, Vim tries to send event notifications to the server before - # it's up. This causes intrusive exception messages to interrupt the user. - # While we do want to log these exceptions just in case, we post them - # quietly to the Vim message log because nothing bad will happen if the - # server misses some events and we don't want to annoy the user. - try: - self.PostDataToHandlerAsync( request_data, 'event_notification' ) - except: - vimsupport.EchoText( traceback.format_exc() ) + self.PostDataToHandlerAsync( request_data, 'event_notification' ) def SendEventNotificationAsync( event_name, extra_data = None ):