Make _spawn_service more flexible

I need to tweak the launcher used, as it stands this isn't possible.
Also I find it ugly muddling the service arguments with the
_spawn_service arguments.

Pass in constructors for each of these. This allows us to pass
whatever arguments, set up extra things, whatever we want. It's
important that at least the launcher is created in the child process
so we can't pass in objects.

This patch also fixes Launcher.launch_service to accept a workers
argument (which must be 1 or a ValueError will be raised). This makes
ServiceLauncher.launch_service compatible with
ProcessLauncher.launch_service, avoiding awkward "if isinstance" or
"if workers == 1" logic when you're not sure of the type of the
launcher.

Change-Id: Ia309828c0c7e7599d4b82994dd36165106dc6513
This commit is contained in:
Alexis Lee 2016-03-07 18:31:38 +00:00
parent c8499ee28a
commit 1393c85f32
2 changed files with 20 additions and 11 deletions

View File

@ -194,14 +194,19 @@ class Launcher(object):
self.backdoor_port = (
eventlet_backdoor.initialize_if_enabled(self.conf))
def launch_service(self, service):
def launch_service(self, service, workers=1):
"""Load and start the given service.
:param service: The service you would like to start, must be an
instance of :class:`oslo_service.service.ServiceBase`
:param workers: This param makes this method compatible with
ProcessLauncher.launch_service. It must be None, 1 or
omitted.
:returns: None
"""
if workers is not None and workers != 1:
raise ValueError(_("Launcher asked to start multiple workers"))
_check_service_base(service)
service.backdoor_port = self.backdoor_port
self.services.add(service)
@ -700,9 +705,8 @@ def launch(conf, service, workers=1):
if workers is None or workers == 1:
launcher = ServiceLauncher(conf)
launcher.launch_service(service)
else:
launcher = ProcessLauncher(conf)
launcher.launch_service(service, workers=workers)
launcher.launch_service(service, workers=workers)
return launcher

View File

@ -84,8 +84,8 @@ class ServiceTestBase(base.ServiceBaseTestCase):
def _spawn_service(self,
workers=1,
service_to_launch=ServiceWithTimer,
*args, **kwargs):
service_maker=None,
launcher_maker=None):
self.workers = workers
pid = os.fork()
if pid == 0:
@ -99,8 +99,12 @@ class ServiceTestBase(base.ServiceBaseTestCase):
# os._exit() which doesn't have this problem.
status = 0
try:
serv = service_to_launch(*args, **kwargs)
launcher = service.launch(self.conf, serv, workers=workers)
serv = service_maker() if service_maker else ServiceWithTimer()
if launcher_maker:
launcher = launcher_maker()
launcher.launch_service(serv, workers=workers)
else:
launcher = service.launch(self.conf, serv, workers=workers)
status = launcher.wait()
except SystemExit as exc:
status = exc.code
@ -212,7 +216,8 @@ class ServiceLauncherTest(ServiceTestBase):
self.assertEqual(os.WEXITSTATUS(status), 0)
def test_crashed_service(self):
self.pid = self._spawn_service(service_to_launch=ServiceCrashOnStart)
service_maker = lambda: ServiceCrashOnStart()
self.pid = self._spawn_service(service_maker=service_maker)
status = self._reap_test()
self.assertTrue(os.WIFEXITED(status))
self.assertEqual(os.WEXITSTATUS(status), 1)
@ -251,8 +256,8 @@ class ServiceRestartTest(ServiceTestBase):
def _spawn(self):
ready_event = multiprocessing.Event()
self.pid = self._spawn_service(workers=1,
ready_event=ready_event)
service_maker = lambda: ServiceWithTimer(ready_event=ready_event)
self.pid = self._spawn_service(service_maker=service_maker)
return ready_event
def test_service_restart(self):
@ -315,7 +320,7 @@ class LauncherTest(base.ServiceBaseTestCase):
def _test_launch_single(self, workers, mock_launch):
svc = service.Service()
service.launch(self.conf, svc, workers=workers)
mock_launch.assert_called_with(svc)
mock_launch.assert_called_with(svc, workers=workers)
def test_launch_none(self):
self._test_launch_single(None)