New ycmd watchdog kills server when idle too long

Defaults are kill server after 12 hours of inactivity; the reason why it's 12
hours and not less is because we don't want to kill the server when the user
just left his machine (and Vim) on during the night.
This commit is contained in:
Strahinja Val Markovic 2013-10-23 11:02:25 -07:00
parent 78107361b3
commit 262d8aad03
4 changed files with 89 additions and 4 deletions

View File

@ -29,6 +29,7 @@
"server_use_vim_stdout": 0,
"server_log_level": "info",
"server_keep_logfiles": 0,
"server_idle_shutdown_seconds": 43200,
"auto_start_csharp_server": 1,
"auto_stop_csharp_server": 1,
"csharp_server_port": 2000

View File

@ -0,0 +1,78 @@
#!/usr/bin/env python
#
# Copyright (C) 2013 Strahinja Val Markovic <val@markovic.io>
#
# This file is part of YouCompleteMe.
#
# YouCompleteMe is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# YouCompleteMe is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>.
import time
import os
import copy
from ycm import utils
from threading import Thread, Lock
# This class implements the Bottle plugin API:
# http://bottlepy.org/docs/dev/plugindev.html
#
# The idea here is to decorate every route handler automatically so that on
# every request, we log when the request was made. Then a watchdog thread checks
# every check_interval_seconds whether the server has been idle for a time
# greater that the passed-in idle_shutdown_seconds. If it has, we kill the
# server.
#
# We want to do this so that if something goes bonkers in Vim and the server
# never gets killed by the client, we don't end up with lots of zombie servers.
class WatchdogPlugin( object ):
name = 'watchdog'
api = 2
def __init__( self,
idle_shutdown_seconds,
check_interval_seconds = 60 * 10 ):
self._check_interval_seconds = check_interval_seconds
self._idle_shutdown_seconds = idle_shutdown_seconds
self._last_request_time = time.time()
self._last_request_time_lock = Lock()
if idle_shutdown_seconds <= 0:
return
self._watchdog_thread = Thread( target = self._WatchdogMain )
self._watchdog_thread.daemon = True
self._watchdog_thread.start()
def _GetLastRequestTime( self ):
with self._last_request_time_lock:
return copy.deepcopy( self._last_request_time )
def _SetLastRequestTime( self, new_value ):
with self._last_request_time_lock:
self._last_request_time = new_value
def _WatchdogMain( self ):
while True:
time.sleep( self._check_interval_seconds )
if time.time() - self._GetLastRequestTime() > self._idle_shutdown_seconds:
utils.TerminateProcess( os.getpid() )
def __call__( self, callback ):
def wrapper( *args, **kwargs ):
self._SetLastRequestTime( time.time() )
return callback( *args, **kwargs )
return wrapper

View File

@ -28,6 +28,7 @@ import waitress
import signal
from ycm import user_options_store
from ycm import extra_conf_store
from ycm.server.watchdog_plugin import WatchdogPlugin
def YcmCoreSanityCheck():
@ -55,6 +56,8 @@ def Main():
parser.add_argument( '--log', type = str, default = 'info',
help = 'log level, one of '
'[debug|info|warning|error|critical]' )
parser.add_argument( '--idle_shutdown_seconds', type = int, default = 0,
help = 'num idle seconds before server shuts down')
parser.add_argument( '--options_file', type = str, default = '',
help = 'file with user options, in JSON format' )
args = parser.parse_args()
@ -79,9 +82,10 @@ def Main():
# This can't be a top-level import because it transitively imports
# ycm_core which we want to be imported ONLY after extra conf
# preload has executed.
import handlers
from ycm.server import handlers
handlers.UpdateUserOptions( options )
SetUpSignalHandler()
handlers.app.install( WatchdogPlugin( args.idle_shutdown_seconds ) )
waitress.serve( handlers.app,
host = args.host,
port = args.port,

View File

@ -41,9 +41,9 @@ try:
except ImportError:
USE_ULTISNIPS_DATA = False
SERVER_CRASH_MESSAGE_STDERR_FILE = 'The ycmd server crashed with output:\n'
SERVER_CRASH_MESSAGE_STDERR_FILE = 'The ycmd server SHUT DOWN with output:\n'
SERVER_CRASH_MESSAGE_SAME_STDERR = (
'The ycmd server crashed, check console output for logs!' )
'The ycmd server shut down, check console output for logs!' )
class YouCompleteMe( object ):
@ -69,7 +69,9 @@ class YouCompleteMe( object ):
_PathToServerScript(),
'--port={0}'.format( server_port ),
'--options_file={0}'.format( options_file.name ),
'--log={0}'.format( self._user_options[ 'server_log_level' ] ) ]
'--log={0}'.format( self._user_options[ 'server_log_level' ] ),
'--idle_shutdown_seconds={0}'.format(
self._user_options[ 'server_idle_shutdown_seconds' ] ) ]
BaseRequest.server_location = 'http://localhost:' + str( server_port )