[Buildbot-commits] buildbot/buildbot/slave commands.py,1.32,1.33

Brian Warner warner at users.sourceforge.net
Tue May 17 04:41:01 UTC 2005


Update of /cvsroot/buildbot/buildbot/buildbot/slave
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10352/buildbot/slave

Modified Files:
	commands.py 
Log Message:
Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-185
Creator:  Brian Warner <warner at monolith.lothar.com>

add retry-VC-checkout control (SF#1200395)

Patches applied:

 * warner at monolith.lothar.com--2005/buildbot--dev--0--patch-29
   Merged from arch at buildbot.sf.net--2004 (patch 175-184)

 * warner at monolith.lothar.com--2005/buildbot--dev--0--patch-30
   add retry-VC-checkout control (SF#1200395)


Index: commands.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/slave/commands.py,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- commands.py	13 May 2005 23:15:34 -0000	1.32
+++ commands.py	17 May 2005 04:40:59 -0000	1.33
@@ -14,6 +14,7 @@
 # version history:
 #  >=1.17: commands are interruptable
 #  >=1.28: Arch understands 'revision', added Bazaar
+#  >=1.33: Source classes understand 'retry'
 
 class CommandInterrupted(Exception):
     pass
@@ -197,24 +198,24 @@
         # obtain the same results. If there are spaces in the arguments, too
         # bad.
         msg = " ".join(argv)
-        log.msg("  " + msg)
+        log.msg(" " + msg)
         self.sendStatus({'header': msg+"\n"})
 
         # then comes the secondary information
-        msg = "in dir %s" % (self.workdir,)
+        msg = " in dir %s" % (self.workdir,)
         if self.timeout:
             msg += " (timeout %d secs)" % (self.timeout,)
-        log.msg("  " + msg)
+        log.msg(" " + msg)
         self.sendStatus({'header': msg+"\n"})
 
         # then the argv array for resolving unambiguity
-        msg = "argv: %s" % (argv,)
-        log.msg("  " + msg)
+        msg = " argv: %s" % (argv,)
+        log.msg(" " + msg)
         self.sendStatus({'header': msg+"\n"})
 
         # then the environment, since it sometimes causes problems
-        msg = "environment: %s" % (self.environ,)
-        log.msg("  " + msg)
+        msg = " environment: %s" % (self.environ,)
+        log.msg(" " + msg)
         self.sendStatus({'header': msg+"\n"})
 
         self.process = reactor.spawnProcess(self.pp, argv[0], argv,
@@ -535,8 +536,14 @@
                         STRIPLEVEL substituted as %d. The command will fail if
                         the patch process fails (rejected hunks).
 
-        - ['timeout']:  seconds of silence tolerated before we kill of the
+        - ['timeout']:  seconds of silence tolerated before we kill off the
                         command
+
+        - ['retry']:    If not None, this is a tuple of (delay, repeats)
+                        which means that any failed VC updates should be
+                        reattempted, up to REPEATS times, after a delay of
+                        DELAY seconds. This is intended to deal with slaves
+                        that experience transient network failures.
     """
 
     def setup(self, args):
@@ -545,6 +552,7 @@
         self.revision = args.get('revision')
         self.patch = args.get('patch')
         self.timeout = args.get('timeout', 120)
+        self.retry = args.get('retry')
         # VC-specific subclasses should override this to extract more args.
         # Make sure to upcall!
 
@@ -583,11 +591,14 @@
             self.command.kill("command interrupted")
 
     def doVC(self, res):
+        if self.interrupted:
+            raise AbandonChain(1)
         if self.sourcedirIsUpdateable():
             d = self.doVCUpdate()
             d.addCallback(self.maybeDoVCFallback)
         else:
             d = self.doVCFull()
+            d.addBoth(self.maybeDoVCRetry)
         d.addCallback(self._abandonOnFailure)
         return d
 
@@ -614,9 +625,45 @@
         self.sendStatus({'header': msg + "\n"})
         log.msg(msg)
         d = self.doVCFull()
+        d.addBoth(self.maybeDoVCRetry)
         d.addCallback(self._abandonOnFailure)
         return d
 
+    def maybeDoVCRetry(self, res):
+        """We get here somewhere after a VC chain has finished. res could
+        be::
+
+         - 0: the operation was successful
+         - nonzero: the operation failed. retry if possible
+         - AbandonChain: the operation failed, someone else noticed. retry.
+         - Failure: some other exception, re-raise
+        """
+
+        if isinstance(res, failure.Failure):
+            if self.interrupted:
+                return res # don't re-try interrupted builds
+            res.trap(AbandonChain)
+        else:
+            if type(res) is int and res == 0:
+                return res
+            if self.interrupted:
+                raise AbandonChain(1)
+        # if we get here, we should retry, if possible
+        if self.retry:
+            delay, repeats = self.retry
+            if repeats >= 0:
+                self.retry = (delay, repeats-1)
+                msg = ("update failed, trying %d more times after %d seconds"
+                       % (repeats, delay))
+                self.sendStatus({'header': msg + "\n"})
+                log.msg(msg)
+                d = defer.Deferred()
+                d.addCallback(lambda res: self.doVCFull())
+                d.addBoth(self.maybeDoVCRetry)
+                reactor.callLater(delay, d.callback, None)
+                return d
+        return res
+
     def doClobber(self, dummy, dirname):
         # TODO: remove the old tree in the background
 ##         workdir = os.path.join(self.builder.basedir, self.workdir)





More information about the Commits mailing list