From 66d45b8e91bf1263c82e636bd21498bf6de552bc Mon Sep 17 00:00:00 2001 From: Bernard Cafarelli Date: Fri, 7 Feb 2020 14:21:09 +0100 Subject: [PATCH] Re-use existing ProcessLauncher from wsgi in RPC workers If both are run under the same process, and api_workers >= 2, the server process will instantiate two oslo_service.ProcessLauncher instances This should be avoided [0], and indeed causes issues on subprocess and signal handling: killed RPC workers not respawning, SIGHUP on master process leading to unresponsive server, signal not properly sent to all child processes, ... To avoid this, use the wsgi ProcessLauncher instance if it exists [0] https://docs.openstack.org/oslo.service/latest/user/usage.html#launchers Conflicts: neutron/service.py Depends-On: https://review.opendev.org/708825/ Change-Id: Ic821f8ca84add9c8137ef712031afb43e491591c Closes-Bug: #1780139 (cherry picked from commit 13aa00026f768642f385259ba7ccddcfdad3c75f) --- neutron/server/wsgi_eventlet.py | 2 +- neutron/service.py | 17 +++++++++++------ neutron/wsgi.py | 6 ++++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/neutron/server/wsgi_eventlet.py b/neutron/server/wsgi_eventlet.py index afd58bcca69..a2b3a342274 100644 --- a/neutron/server/wsgi_eventlet.py +++ b/neutron/server/wsgi_eventlet.py @@ -27,7 +27,7 @@ def eventlet_wsgi_server(): def start_api_and_rpc_workers(neutron_api): try: - worker_launcher = service.start_all_workers() + worker_launcher = service.start_all_workers(neutron_api) pool = eventlet.GreenPool() api_thread = pool.spawn(neutron_api.wait) diff --git a/neutron/service.py b/neutron/service.py index f31f44c01c2..1ae6e74f7a0 100644 --- a/neutron/service.py +++ b/neutron/service.py @@ -217,7 +217,7 @@ class AllServicesNeutronWorker(neutron_worker.BaseWorker): self._launcher.restart() -def _start_workers(workers): +def _start_workers(workers, neutron_api=None): process_workers = [ plugin_worker for plugin_worker in workers if plugin_worker.worker_process_count > 0 @@ -225,9 +225,14 @@ def _start_workers(workers): try: if process_workers: - worker_launcher = common_service.ProcessLauncher( - cfg.CONF, wait_interval=1.0 - ) + # Get eventual already existing instance from WSGI app + worker_launcher = None + if neutron_api: + worker_launcher = neutron_api.wsgi_app.process_launcher + if worker_launcher is None: + worker_launcher = common_service.ProcessLauncher( + cfg.CONF, wait_interval=1.0 + ) # add extra process worker and spawn there all workers with # worker_process_count == 0 @@ -259,9 +264,9 @@ def _start_workers(workers): 'details.') -def start_all_workers(): +def start_all_workers(neutron_api=None): workers = _get_rpc_workers() + _get_plugins_workers() - launcher = _start_workers(workers) + launcher = _start_workers(workers, neutron_api) registry.publish(resources.PROCESS, events.AFTER_SPAWN, None) return launcher diff --git a/neutron/wsgi.py b/neutron/wsgi.py index a17ff5eccfc..a4caf6f54c3 100644 --- a/neutron/wsgi.py +++ b/neutron/wsgi.py @@ -224,6 +224,12 @@ class Server(object): log_format=CONF.wsgi_log_format, socket_timeout=self.client_socket_timeout) + @property + def process_launcher(self): + if isinstance(self._server, common_service.ProcessLauncher): + return self._server + return None + class Request(wsgi.Request):