From: Brian Warner Date: Thu, 8 Mar 2007 22:10:36 +0000 (-0700) Subject: rearrange service startup a bit, now Node.startService() returns a Deferred that... X-Git-Url: https://git.rkrishnan.org/listings/specifications/reliability?a=commitdiff_plain;h=78d19c271c94c8cdfec3fb8807fee4c14a9d9bcd;p=tahoe-lafs%2Ftahoe-lafs.git rearrange service startup a bit, now Node.startService() returns a Deferred that fires when the tub is actually ready, and there is also a Node.when_tub_ready() hook. This allows get_local_addresses() to be slow and not break everything. Changed all necessary test cases to accomodate this slow startup. --- diff --git a/src/allmydata/client.py b/src/allmydata/client.py index 53956915..f0b3927b 100644 --- a/src/allmydata/client.py +++ b/src/allmydata/client.py @@ -29,6 +29,7 @@ class Client(node.Node, Referenceable): def __init__(self, basedir="."): node.Node.__init__(self, basedir) self.queen = None # self.queen is either None or a RemoteReference + self.my_pburl = None self.all_peers = set() self.peer_pburls = {} self.connections = {} diff --git a/src/allmydata/node.py b/src/allmydata/node.py index db45ac93..da656a19 100644 --- a/src/allmydata/node.py +++ b/src/allmydata/node.py @@ -1,10 +1,11 @@ -from twisted.application import service import os.path +from twisted.python import log +from twisted.application import service +from twisted.internet import defer from foolscap import Tub from allmydata.util.iputil import get_local_addresses -from allmydata.util import idlib -from twisted.python import log +from allmydata.util import idlib, observer class Node(service.MultiService): # this implements common functionality of both Client nodes and the Queen @@ -18,6 +19,7 @@ class Node(service.MultiService): def __init__(self, basedir="."): service.MultiService.__init__(self) self.basedir = os.path.abspath(basedir) + self._tub_ready_observerlist = observer.OneShotObserverList() assert self.CERTFILE, "Your node.Node subclass must provide CERTFILE" certfile = os.path.join(self.basedir, self.CERTFILE) if os.path.exists(certfile): @@ -55,6 +57,37 @@ class Node(service.MultiService): m.setServiceParent(self) self.log("AuthorizedKeysManhole listening on %d" % portnum) + def startService(self): + """Start the node. Returns a Deferred that fires (with self) when it + is ready to go. + + Many callers don't pay attention to the return value from + startService, since they aren't going to do anything special when it + finishes. If they are (for example unit tests which need to wait for + the node to fully start up before it gets shut down), they can wait + for the Deferred I return to fire. In particular, you should wait for + my startService() Deferred to fire before you call my stopService() + method. + """ + + # note: this class can only be started and stopped once. + service.MultiService.startService(self) + d = defer.succeed(None) + d.addCallback(lambda res: get_local_addresses()) + d.addCallback(self._setup_tub) + d.addCallback(lambda res: self.tub_ready()) + def _ready(res): + self.log("%s running" % self.NODETYPE) + self._tub_ready_observerlist.fire(self) + return self + d.addCallback(_ready) + return d + + def shutdown(self): + """Shut down the node. Returns a Deferred that fires (with None) when + it finally stops kicking.""" + return self.stopService() + def log(self, msg): log.msg(self.short_nodeid + ": " + msg) @@ -86,15 +119,10 @@ class Node(service.MultiService): # called when the Tub is available for registerReference pass + def when_tub_ready(self): + return self._tub_ready_observerlist.when_fired() + def add_service(self, s): s.setServiceParent(self) return s - def startService(self): - # note: this class can only be started and stopped once. - service.MultiService.startService(self) - local_addresses = get_local_addresses() - self._setup_tub(local_addresses) - self.tub_ready() - self.log("%s running" % self.NODETYPE) - diff --git a/src/allmydata/test/test_client.py b/src/allmydata/test/test_client.py index 5cd01e06..eee9dbc9 100644 --- a/src/allmydata/test/test_client.py +++ b/src/allmydata/test/test_client.py @@ -6,8 +6,9 @@ from allmydata import client class Basic(unittest.TestCase): def test_loadable(self): c = client.Client("") - c.startService() - return c.stopService() + d = c.startService() + d.addCallback(lambda res: c.stopService()) + return d def test_permute(self): c = client.Client("") diff --git a/src/allmydata/test/test_queen.py b/src/allmydata/test/test_queen.py index 7e12917a..0a242c4c 100644 --- a/src/allmydata/test/test_queen.py +++ b/src/allmydata/test/test_queen.py @@ -6,5 +6,7 @@ from allmydata import queen class Basic(unittest.TestCase): def test_loadable(self): q = queen.Queen() - q.startService() - return q.stopService() + d = q.startService() + d.addCallback(lambda res: q.stopService()) + return d + diff --git a/src/allmydata/test/test_storage.py b/src/allmydata/test/test_storage.py index dcc4035e..31da06ab 100644 --- a/src/allmydata/test/test_storage.py +++ b/src/allmydata/test/test_storage.py @@ -21,7 +21,8 @@ class StorageTest(unittest.TestCase): self.node.setServiceParent(self.svc) self.tub = Tub() self.tub.setServiceParent(self.svc) - return self.svc.startService() + self.svc.startService() + return self.node.when_tub_ready() def test_create_bucket(self): """ diff --git a/src/allmydata/test/test_system.py b/src/allmydata/test/test_system.py index 3ebc49f1..0ec50774 100644 --- a/src/allmydata/test/test_system.py +++ b/src/allmydata/test/test_system.py @@ -40,10 +40,16 @@ class SystemTest(unittest.TestCase): self.numclients = NUMCLIENTS if not os.path.isdir("queen"): os.mkdir("queen") - q = self.queen = self.add_service(queen.Queen(basedir="queen")) + self.queen = self.add_service(queen.Queen(basedir="queen")) + d = self.queen.when_tub_ready() + d.addCallback(self._set_up_nodes_2) + return d + + def _set_up_nodes_2(self, res): + q = self.queen self.queen_pburl = q.urls["roster"] self.clients = [] - for i in range(NUMCLIENTS): + for i in range(self.numclients): basedir = "client%d" % i if not os.path.isdir(basedir): os.mkdir(basedir)