Add 2 new states to Component: Starting and Stopping

Fix issue where a Component could have it's start and stop methods called more than once while waiting for their deferreds to fire
This commit is contained in:
Andrew Resch 2010-03-27 20:05:20 -07:00
parent 46a6576c68
commit 7be5b4c8bc
2 changed files with 40 additions and 7 deletions

View File

@ -68,17 +68,23 @@ class Component(object):
call to stop() will be issued prior to shutdown().
**States:**
A Component can be in one of these 3 states.
A Component can be in one of these 5 states.
**Started** - The Component has been started by the :class:`ComponentRegistry`
and will have it's update timer started.
**Starting** - The Component has had it's start method called, but it hasn't
fully started yet.
**Stopped** - The Component has either been stopped or has yet to be started.
**Stopping** - The Component has had it's stop method called, but it hasn't
fully stopped yet.
**Paused** - The Component has had it's update timer stopped, but will
still be considered in a Started state.
"""
def __init__(self, name, interval=1, depend=None):
self._component_name = name
@ -86,6 +92,8 @@ class Component(object):
self._component_depend = depend
self._component_state = "Stopped"
self._component_timer = None
self._component_starting_deferred = None
self._component_stopping_deferred = None
_ComponentRegistry.register(self)
def _component_start_timer(self):
@ -96,15 +104,20 @@ class Component(object):
def _component_start(self):
def on_start(result):
self._component_state = "Started"
self._component_starting_deferred = None
self._component_start_timer()
return True
if self._component_state == "Stopped":
if hasattr(self, "start"):
self._component_state = "Starting"
d = maybeDeferred(self.start)
d.addCallback(on_start)
self._component_starting_deferred = d
else:
d = maybeDeferred(on_start, None)
elif self._component_state == "Starting":
return self._component_starting_deferred
elif self._component_state == "Started":
d = succeed(True)
else:
@ -119,13 +132,18 @@ class Component(object):
self._component_timer.stop()
return True
if self._component_state != "Stopped":
if self._component_state != "Stopped" and self._component_state != "Stopping":
if hasattr(self, "stop"):
self._component_state = "Stopping"
d = maybeDeferred(self.stop)
d.addCallback(on_stop)
self._component_stopping_deferred = d
else:
d = maybeDeferred(on_stop, None)
if self._component_state == "Stopping":
return self._component_stopping_deferred
return succeed(None)
def _component_pause(self):

View File

@ -6,10 +6,14 @@ class testcomponent(component.Component):
def __init__(self, name):
component.Component.__init__(self, name)
self.start_count = 0
self.stop_count = 0
def start(self):
self.start_count += 1
def stop(self):
self.stop_count += 1
class testcomponent_delaystart(testcomponent):
def start(self):
def do_sleep():
@ -25,18 +29,26 @@ class testcomponent_update(component.Component):
component.Component.__init__(self, name)
self.counter = 0
self.start_count = 0
self.stop_count = 0
def update(self):
self.counter += 1
def stop(self):
self.stop_count += 1
class testcomponent_shutdown(component.Component):
def __init__(self, name):
component.Component.__init__(self, name)
self.shutdowned = False
self.stop_count = 0
def shutdown(self):
self.shutdowned = True
def stop(self):
self.stop_count += 1
class ComponentTestClass(unittest.TestCase):
def tearDown(self):
component._ComponentRegistry.components = {}
@ -106,6 +118,7 @@ class ComponentTestClass(unittest.TestCase):
def on_stop(result, c):
self.assertEquals(c._component_state, "Stopped")
self.assertFalse(c._component_timer.running)
self.assertEquals(c.stop_count, 1)
def on_start(result, c):
self.assertEquals(c._component_state, "Started")
@ -120,6 +133,7 @@ class ComponentTestClass(unittest.TestCase):
def on_stop(*args):
for c in args[1:]:
self.assertEquals(c._component_state, "Stopped")
self.assertEquals(c.stop_count, 1)
def on_start(*args):
for c in args[1:]:
@ -169,6 +183,7 @@ class ComponentTestClass(unittest.TestCase):
def on_shutdown(result, c1):
self.assertTrue(c1.shutdowned)
self.assertEquals(c1._component_state, "Stopped")
self.assertEquals(c1.stop_count, 1)
def on_start(result, c1):
d = component.shutdown()