3.1.8. Writing Schedulers¶
Buildbot schedulers are the process objects responsible for requesting builds.
Schedulers are free to decide when to request builds, and to define the parameters of the builds.
Many schedulers (e.g., SingleBranchScheduler
) request builds in response to changes from change sources.
Others, such as Nightly
, request builds at specific times.
Still others, like ForceScheduler
, Try_Jobdir
, or Triggerable
, respond to external inputs.
Each scheduler has a unique name, and within a Buildbot cluster, can be active on at most one master. If a scheduler is configured on multiple masters, it will be inactive on all but one master. This provides a form of non-revertive failover for schedulers: if an active scheduler's master fails, an inactive instance of that scheduler on another master will become active.
3.1.8.1. API Stability¶
Until Buildbot reaches version 1.0.0, API stability is not guaranteed. The instructions in this document may change incompatibly until that time.
3.1.8.2. Implementing A Scheduler¶
A scheduler is a subclass of BaseScheduler
.
The constructor's arguments form the scheduler's configuration.
The first two arguments are name
and builderNames
, and are positional.
The remaining arguments are keyword arguments, and the subclass's constructor should accept **kwargs
to pass on to the parent class along with the positional arguments.
class MyScheduler(base.BaseScheduler):
def __init__(self, name, builderNames, arg1=None, arg2=None, **kwargs):
base.BaseScheduler.__init__(self, name, builderNames, **kwargs)
self.arg1 = arg1
self.arg2 = arg2
Schedulers are Twisted services, so they can implement startService
and stopService
.
However, it is more common for scheduler subclasses to override startActivity
and stopActivity
instead.
See below.
3.1.8.3. Consuming Changes¶
A scheduler that needs to be notified of new changes should call startConsumingChanges
when it becomes active.
Change consumption will automatically stop when the scheduler becomes inactive.
Once consumption has started, the gotChange
method is invoked for each new change.
The scheduler is free to do whatever it likes in this method.
3.1.8.4. Adding Buildsets¶
To add a new buildset, subclasses should call one of the parent-class methods with the prefix addBuildsetFor
.
These methods call addBuildset
after applying behaviors common to all schedulers
Any of these methods can be called at any time.
3.1.8.5. Handling Reconfiguration¶
When the configuration for a scheduler changes, Buildbot deactivates, stops and removes the old scheduler, then adds, starts, and maybe activates the new scheduler.
Buildbot determines whether a scheduler has changed by subclassing ComparableMixin
.
See the documentation for class for an explanation of the compare_attrs
attribute.
Note
In a future version, schedulers will be converted to handle reconfiguration as reconfigurable services, and will no longer require compare_attrs
to be set.
3.1.8.6. Becoming Active and Inactive¶
An inactive scheduler should not do anything that might interfere with an active scheduler of the same name.
Simple schedulers can consult the active
attribute to determine whether the scheduler is active.
Most schedulers, however, will implement the activate
method to begin any processing expected of an active scheduler.
That may involve calling startConsumingChanges
, beginning a LoopingCall
, or subscribing to messages.
Any processing begun by the activate
method, or by an active scheduler, should be stopped by the deactivate
method.
The deactivate
method's Deferred should not fire until such processing has completely stopped.
Schedulers must up-call the parent class's activate
and deactivate
methods!
3.1.8.7. Keeping State¶
The BaseScheduler
class provides getState
and setState
methods to get and set state values for the scheduler.
Active scheduler instances should use these functions to store persistent scheduler state, such that if they fail or become inactive, other instances can pick up where they leave off.
A scheduler can cache its state locally, only calling getState
when it first becomes active.
However, it is best to keep the state as up-to-date as possible, by calling setState
any time the state changes.
This prevents loss of state from an unexpected master failure.
Note that the state-related methods do not use locks of any sort. It is up to the caller to ensure that no race conditions exist between getting and setting state. Generally, it is sufficient to rely on there being only one running instance of a scheduler, and cache state in memory.