Merge "Add setproctitle support to the workers module"
This commit is contained in:
commit
66c415280a
@ -78,6 +78,7 @@ requests==2.14.2
|
||||
requestsexceptions==1.2.0
|
||||
rfc3986==0.3.1
|
||||
Routes==2.3.1
|
||||
setproctitle==1.1.10
|
||||
six==1.10.0
|
||||
snowballstemmer==1.2.1
|
||||
Sphinx==1.6.2
|
||||
|
@ -12,6 +12,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import six
|
||||
|
||||
import mock
|
||||
|
||||
from neutron_lib.callbacks import events
|
||||
@ -34,6 +36,14 @@ class _BaseWorker(worker.BaseWorker):
|
||||
pass
|
||||
|
||||
|
||||
# Same as _BaseWorker, but looks like a process launch instead of eventlet
|
||||
class _ProcWorker(_BaseWorker):
|
||||
|
||||
def __init__(self, worker_process_count=1, set_proctitle='on'):
|
||||
super(_ProcWorker, self).__init__(worker_process_count, set_proctitle)
|
||||
self._my_pid = -1 # make it appear to be a separate process
|
||||
|
||||
|
||||
class TestBaseWorker(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
@ -51,3 +61,77 @@ class TestBaseWorker(base.BaseTestCase):
|
||||
base_worker.start()
|
||||
self._reg.notify.assert_called_once_with(
|
||||
resources.PROCESS, events.AFTER_INIT, base_worker.start)
|
||||
|
||||
# Forked workers, should call setproctitle
|
||||
|
||||
def test_proctitle_default(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_ProcWorker().start()
|
||||
six.assertRegex(self, spt.call_args[0][0],
|
||||
'^neutron-server: _ProcWorker \(.*python.*\)$')
|
||||
|
||||
def test_proctitle_custom_desc(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_ProcWorker().start(desc="fancy title")
|
||||
six.assertRegex(self, spt.call_args[0][0],
|
||||
'^neutron-server: fancy title \(.*python.*\)$')
|
||||
|
||||
def test_proctitle_custom_name(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_ProcWorker().start(name="tardis")
|
||||
six.assertRegex(self, spt.call_args[0][0],
|
||||
'^tardis: _ProcWorker \(.*python.*\)$')
|
||||
|
||||
def test_proctitle_empty(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_ProcWorker().start(desc="")
|
||||
six.assertRegex(self, spt.call_args[0][0],
|
||||
'^neutron-server: _ProcWorker \(.*python.*\)$')
|
||||
|
||||
def test_proctitle_nonstring(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_ProcWorker().start(desc=2)
|
||||
six.assertRegex(self, spt.call_args[0][0],
|
||||
'^neutron-server: 2 \(.*python.*\)$')
|
||||
|
||||
def test_proctitle_both_empty(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_ProcWorker().start(name="", desc="")
|
||||
six.assertRegex(self, spt.call_args[0][0],
|
||||
'^: _ProcWorker \(.*python.*\)$')
|
||||
|
||||
def test_proctitle_name_none(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_ProcWorker().start(name=None)
|
||||
six.assertRegex(self, spt.call_args[0][0],
|
||||
'^None: _ProcWorker \(.*python.*\)$')
|
||||
|
||||
# Forked, but proctitle disabled
|
||||
|
||||
def test_proctitle_off(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_ProcWorker(set_proctitle='off').start()
|
||||
self.assertIsNone(spt.call_args)
|
||||
|
||||
# Eventlet style worker, should never call setproctitle
|
||||
|
||||
def test_proctitle_same_process(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_BaseWorker().start()
|
||||
self.assertIsNone(spt.call_args)
|
||||
|
||||
def test_setproctitle_on(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_ProcWorker(set_proctitle='on').start(name="foo", desc="bar")
|
||||
six.assertRegex(self, spt.call_args[0][0],
|
||||
'^foo: bar \(.*python.*\)$')
|
||||
|
||||
def test_setproctitle_off(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_ProcWorker(set_proctitle='off').start(name="foo", desc="bar")
|
||||
self.assertIsNone(spt.call_args)
|
||||
|
||||
def test_setproctitle_brief(self):
|
||||
with mock.patch('setproctitle.setproctitle') as spt:
|
||||
_ProcWorker(set_proctitle='brief').start(name="foo", desc="bar")
|
||||
self.assertEqual(spt.call_args[0][0], 'foo: bar')
|
||||
|
@ -12,7 +12,10 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
|
||||
from oslo_service import service
|
||||
import setproctitle
|
||||
|
||||
from neutron_lib.callbacks import events
|
||||
from neutron_lib.callbacks import registry
|
||||
@ -45,15 +48,24 @@ class BaseWorker(service.ServiceBase):
|
||||
# default class value for case when super().__init__ is not called
|
||||
_default_process_count = 1
|
||||
|
||||
def __init__(self, worker_process_count=_default_process_count):
|
||||
def __init__(self, worker_process_count=_default_process_count,
|
||||
set_proctitle='on'):
|
||||
"""Initialize a worker instance.
|
||||
|
||||
:param worker_process_count: Defines how many processes to spawn for
|
||||
worker:
|
||||
0 - spawn 1 new worker thread,
|
||||
1..N - spawn N new worker processes
|
||||
set_proctitle:
|
||||
'off' - do not change process title
|
||||
'on' - set process title to descriptive string and parent
|
||||
'brief' - set process title to descriptive string
|
||||
"""
|
||||
self._worker_process_count = worker_process_count
|
||||
self._my_pid = os.getpid()
|
||||
self._set_proctitle = set_proctitle
|
||||
if set_proctitle == 'on':
|
||||
self._parent_proctitle = setproctitle.getproctitle()
|
||||
|
||||
@property
|
||||
def worker_process_count(self):
|
||||
@ -63,13 +75,33 @@ class BaseWorker(service.ServiceBase):
|
||||
"""
|
||||
return self._worker_process_count
|
||||
|
||||
def start(self):
|
||||
def setproctitle(self, name="neutron-server", desc=None):
|
||||
if self._set_proctitle == "off" or os.getpid() == self._my_pid:
|
||||
return
|
||||
|
||||
if not desc:
|
||||
desc = self.__class__.__name__
|
||||
|
||||
proctitle = "%s: %s" % (name, desc)
|
||||
if self._set_proctitle == "on":
|
||||
proctitle += " (%s)" % self._parent_proctitle
|
||||
|
||||
setproctitle.setproctitle(proctitle)
|
||||
|
||||
def start(self, name="neutron-server", desc=None):
|
||||
"""Start the worker.
|
||||
|
||||
If worker_process_count is greater than 0, a callback notification
|
||||
is sent. Subclasses should call this method before doing their
|
||||
own start() work.
|
||||
|
||||
Automatically sets the process title to indicate that this is a
|
||||
child worker, customizable via the name and desc arguments.
|
||||
|
||||
:returns: None
|
||||
"""
|
||||
|
||||
# If we are a child process, set our proctitle to something useful
|
||||
self.setproctitle(name, desc)
|
||||
if self.worker_process_count > 0:
|
||||
registry.notify(resources.PROCESS, events.AFTER_INIT, self.start)
|
||||
|
@ -0,0 +1,27 @@
|
||||
features:
|
||||
- |
|
||||
``neutron_lib.worker.BaseWorker`` will now set the process title
|
||||
on process start, if it is a new process. By default, the name
|
||||
will be "neutron-server", and the description will be the name
|
||||
of the worker class, followed by the original process title.
|
||||
Both fields are customizable via the ``name`` and ``desc``
|
||||
arguments to ``BaseWorker.start()``, and the change
|
||||
can be disabled via the ``set_proctitle`` argument to the
|
||||
``__init__`` function. ``neutron.conf`` will have a setting
|
||||
for disabling this functionality for all in-tree workers, but
|
||||
by default, all out of tree plugin workers will set their name
|
||||
at fork time. Available settings are 'on' (described above, and
|
||||
the default), 'off' (same as today), or 'brief', which settings
|
||||
the process name to just name and description. 'brief' is probably
|
||||
most useful/simple for deployers, but 'on' is the default in order
|
||||
to prevent as many script related breakages as possible.
|
||||
upgrade:
|
||||
- Any plugin which forks worker processes from neutron-server will
|
||||
have its proctitle set to "neutron-server" plus a classname in ps
|
||||
output. Any tool used for monitoring/maintenance that watches
|
||||
the process table should be modified to only look for the string
|
||||
``neutron-server``. On the plus side, it will now be possible
|
||||
to distinguish which process belongs to which plugin, based on
|
||||
the new naming. Note that the original process string is still
|
||||
in the proctitle, so as long as the scripting is not looking for
|
||||
a perfect string match, it should continue to work.
|
@ -22,6 +22,7 @@ oslo.service!=1.28.1,>=1.24.0 # Apache-2.0
|
||||
oslo.utils>=3.33.0 # Apache-2.0
|
||||
oslo.versionedobjects>=1.31.2 # Apache-2.0
|
||||
osprofiler>=1.4.0 # Apache-2.0
|
||||
setproctitle>=1.1.10 # BSD
|
||||
WebOb>=1.7.1 # MIT
|
||||
weakrefmethod>=1.0.2;python_version=='2.7' # PSF
|
||||
os-traits>=0.9.0 # Apache-2.0
|
||||
|
Loading…
Reference in New Issue
Block a user