From 442fc2234e8500fb11633d8d8ee7dfe5492fa4a3 Mon Sep 17 00:00:00 2001 From: Clif Houck Date: Tue, 30 Dec 2014 15:02:59 -0600 Subject: [PATCH] Added graceful argument on Service.stop method This change adds a graceful shutdown arugment to the Service.stop method in order to allow a service to gracefully wait for threads to shutdown. Since threadgroup already supports a graceful shutdown argument for its stop() method, it is trivial to support. Added unit tests to demonstrate the expected behavior between graceful and ungraceful service stop()s. Change-Id: Ibc0df09daef5e2a07f232543f44f2fc4d203511c Closes-Bug: 1406638 --- openstack/common/service.py | 4 ++-- tests/unit/test_service.py | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/openstack/common/service.py b/openstack/common/service.py index cbd300b73..a41a29538 100644 --- a/openstack/common/service.py +++ b/openstack/common/service.py @@ -434,8 +434,8 @@ def reset(self): def start(self): pass - def stop(self): - self.tg.stop() + def stop(self, graceful=False): + self.tg.stop(graceful) self.tg.wait() # Signal that service cleanup is done: if not self._done.ready(): diff --git a/tests/unit/test_service.py b/tests/unit/test_service.py index 2f9f774b6..4d9ecc098 100644 --- a/tests/unit/test_service.py +++ b/tests/unit/test_service.py @@ -273,7 +273,6 @@ def stop(self): class LauncherTest(test_base.BaseTestCase): - def setUp(self): super(LauncherTest, self).setUp() self.mox = self.useFixture(moxstubout.MoxStubout()).mox @@ -387,3 +386,38 @@ def test_stop(self): self.assertEqual([mock.call(22, signal.SIGTERM), mock.call(222, signal.SIGTERM)], mock_kill.mock_calls) + + +class GracefulShutdownTestService(service.Service): + def __init__(self): + super(GracefulShutdownTestService, self).__init__() + self.finished_task = event.Event() + + def start(self, sleep_amount): + def sleep_and_send(finish_event): + time.sleep(sleep_amount) + finish_event.send() + self.tg.add_thread(sleep_and_send, self.finished_task) + + +def exercise_graceful_test_service(sleep_amount, time_to_wait, graceful): + svc = GracefulShutdownTestService() + svc.start(sleep_amount) + svc.stop(graceful) + + def wait_for_task(svc): + svc.finished_task.wait() + + return eventlet.timeout.with_timeout(time_to_wait, wait_for_task, + svc=svc, timeout_value="Timeout!") + + +class ServiceTest(test_base.BaseTestCase): + def test_graceful_stop(self): + # Here we wait long enough for the task to gracefully finish. + self.assertEqual(None, exercise_graceful_test_service(1, 2, True)) + + def test_ungraceful_stop(self): + # Here we stop ungracefully, and will never see the task finish. + self.assertEqual("Timeout!", + exercise_graceful_test_service(1, 2, False))