Shutdown TCP ServerSocket when parent process ends (#655) · deepnote/python-lsp-server@e6421d9 · GitHub
Skip to content

Commit e6421d9

Browse files
andfoyccordoba12
authored andcommitted
Shutdown TCP ServerSocket when parent process ends (python-lsp#655)
1 parent 882117f commit e6421d9

3 files changed

Lines changed: 44 additions & 20 deletions

File tree

‎appveyor.yml‎

Lines changed: 5 additions & 0 deletions

‎pyls/python_ls.py‎

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,28 @@ def setup(self):
3434

3535
def handle(self):
3636
self.delegate.start()
37+
# pylint: disable=no-member
38+
self.SHUTDOWN_CALL()
3739

3840

3941
def start_tcp_lang_server(bind_addr, port, check_parent_process, handler_class):
4042
if not issubclass(handler_class, PythonLanguageServer):
4143
raise ValueError('Handler class must be an instance of PythonLanguageServer')
4244

45+
def shutdown_server(*args):
46+
# pylint: disable=unused-argument
47+
log.debug('Shutting down server')
48+
# Shutdown call must be done on a thread, to prevent deadlocks
49+
stop_thread = threading.Thread(target=server.shutdown)
50+
stop_thread.start()
51+
4352
# Construct a custom wrapper class around the user's handler_class
4453
wrapper_class = type(
4554
handler_class.__name__ + 'Handler',
4655
(_StreamHandlerWrapper,),
4756
{'DELEGATE_CLASS': partial(handler_class,
48-
check_parent_process=check_parent_process)}
57+
check_parent_process=check_parent_process),
58+
'SHUTDOWN_CALL': shutdown_server}
4959
)
5060

5161
server = socketserver.TCPServer((bind_addr, port), wrapper_class)
@@ -78,6 +88,7 @@ def __init__(self, rx, tx, check_parent_process=False):
7888
self.workspace = None
7989
self.config = None
8090
self.root_uri = None
91+
self.watching_thread = None
8192
self.workspaces = {}
8293
self.uri_workspace_mapper = {}
8394

@@ -187,19 +198,18 @@ def m_initialize(self, processId=None, rootUri=None, rootPath=None, initializati
187198
self._dispatchers = self._hook('pyls_dispatchers')
188199
self._hook('pyls_initialize')
189200

190-
if self._check_parent_process and processId is not None:
201+
if self._check_parent_process and processId is not None and self.watching_thread is None:
191202
def watch_parent_process(pid):
192203
# exit when the given pid is not alive
193204
if not _utils.is_process_alive(pid):
194205
log.info("parent process %s is not alive", pid)
195206
self.m_exit()
196-
log.debug("parent process %s is still alive", pid)
197-
threading.Timer(PARENT_PROCESS_WATCH_INTERVAL, watch_parent_process, args=[pid]).start()
198-
199-
watching_thread = threading.Thread(target=watch_parent_process, args=(processId,))
200-
watching_thread.daemon = True
201-
watching_thread.start()
207+
else:
208+
threading.Timer(PARENT_PROCESS_WATCH_INTERVAL, watch_parent_process, args=[pid]).start()
202209

210+
self.watching_thread = threading.Thread(target=watch_parent_process, args=(processId,))
211+
self.watching_thread.daemon = True
212+
self.watching_thread.start()
203213
# Get our capabilities
204214
return {'capabilities': self.capabilities()}
205215

‎test/test_language_server.py‎

Lines changed: 21 additions & 12 deletions

0 commit comments

Comments
 (0)