[Buildbot-devel] Continuous scheduler

Brian Warner warner-buildbot at lothar.com
Mon Mar 5 20:26:28 UTC 2007


Patrick Farrell <cyan at compsoc.nuigalway.ie> writes:

> I'm trying to write a scheduler that runs
> its job again as soon as it finishes.

>          def SparkBuildAgain(self, ss):
>                  bs = buildset.BuildSet(self.builderNames,
>                        SourceStamp(changes=ss))
>                  self.submit(bs)

> but it appears that SparkBuildAgain is never called, even
> though it is in the self.successWatchers list.

The most immediate problem is a bootstrap issue: the successWatchers list
will be fired when a build completes successfully, but a build must be
triggered first, and there's nothing in this class to trigger that initial
build.

A secondary problem is that this would only trigger a new build if the
previous one completed successfully, so the first time a build failed, the
loop would terminate. You probably want to ignore the results of the previous
build when starting a new one.

I'd suggest something like the following:


from twisted.internet import reactor
from buildbot import scheduler, sourcestamp, buildset

class ContinuousBuildScheduler(scheduler.BaseScheduler):
    def startService(self):
        scheduler.BaseScheduler.startService(self)
        reactor.callLater(0, self.fire)
    def fire(self):
        bs = buildset.BuildSet([BUILDERNAMES],
                               sourcestamp.SourceStamp(), # build HEAD
                               "continuous scheduler said to build")
        d = bs.waitUntilFinished()
        self.parent.submitBuildSet(bs)
        d.addCallback(self.buildFinished)
    def buildFinished(self, bss):
        # you could use bss.getResults() to examine the results
        self.fire()


The reactor.callLater() is there to put off the first build until a moment
after startService() is called, to make sure that all other services have a
chance to start before the build itself is started. BUILDERNAMES is a list of
builder names, which could have just a single builder if that's all you need.
When all of the builders are finished with the first build, buildFinished()
is called, which restarts the whole process.

By using d.addCallback instead of d.addBoth, we stop looping if the build
experiences an exception of some sort, like if one of the buildernames is
wrong. This is useful because otherwise we'd probably spend 100% cpu making
the same error over and over again. If the build executes normally (but
bss.getResults() returns FAILED to indicate a compile or test failure), the
build still loops. Exceptions are distinct from build failures.


hope that helps,
 -Brian




More information about the devel mailing list