Skip to content

Commit f3d26a3

Browse files
committed
Fix build controller performance issues
Calls policy completed build processing as soon as it's marked Complete instead of doing it when the build is handled by the BuildController. Uses a build.openshift.io/accepted annotation to bump a build so the BuildController can see it in its queue before the next Resync.
1 parent 6822a9b commit f3d26a3

File tree

6 files changed

+40
-26
lines changed

6 files changed

+40
-26
lines changed

pkg/build/api/types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ const (
5454
// BuildConfigPausedAnnotation is an annotation that marks a BuildConfig as paused.
5555
// New Builds cannot be instantiated from a paused BuildConfig.
5656
BuildConfigPausedAnnotation = "openshift.io/build-config.paused"
57+
// BuildAcceptedAnnotation is an annotation used to update a build that can now be
58+
// run based on the RunPolicy (e.g. Serial). Updating the build with this annotation
59+
// forces the build to be processed by the build controller queue without waiting
60+
// for a resync.
61+
BuildAcceptedAnnotation = "build.openshift.io/accepted"
5762
)
5863

5964
// +genclient=true

pkg/build/controller/controller.go

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -96,18 +96,6 @@ func (bc *BuildController) HandleBuild(build *buildapi.Build) error {
9696
}
9797
glog.V(4).Infof("Handling build %s/%s (%s)", build.Namespace, build.Name, build.Status.Phase)
9898

99-
runPolicy := policy.ForBuild(build, bc.RunPolicies)
100-
if runPolicy == nil {
101-
return fmt.Errorf("unable to determine build scheduler for %s/%s", build.Namespace, build.Name)
102-
}
103-
104-
if buildutil.IsBuildComplete(build) {
105-
if err := runPolicy.OnComplete(build); err != nil {
106-
return err
107-
}
108-
return nil
109-
}
110-
11199
// A cancelling event was triggered for the build, delete its pod and update build status.
112100
if build.Status.Cancelled && build.Status.Phase != buildapi.BuildPhaseCancelled {
113101
glog.V(5).Infof("Marking build %s/%s as cancelled", build.Namespace, build.Name)
@@ -126,6 +114,11 @@ func (bc *BuildController) HandleBuild(build *buildapi.Build) error {
126114
return nil
127115
}
128116

117+
runPolicy := policy.ForBuild(build, bc.RunPolicies)
118+
if runPolicy == nil {
119+
return fmt.Errorf("unable to determine build scheduler for %s/%s", build.Namespace, build.Name)
120+
}
121+
129122
// The runPolicy decides whether to execute this build or not.
130123
if run, err := runPolicy.IsRunnable(build); err != nil || !run {
131124
return err
@@ -286,6 +279,7 @@ type BuildPodController struct {
286279
BuildUpdater buildclient.BuildUpdater
287280
SecretClient kcoreclient.SecretsGetter
288281
PodManager podManager
282+
RunPolicies []policy.RunPolicy
289283
}
290284

291285
// HandlePod updates the state of the build based on the pod state
@@ -373,6 +367,17 @@ func (bc *BuildPodController) HandlePod(pod *kapi.Pod) error {
373367
return fmt.Errorf("failed to update build %s/%s: %v", build.Namespace, build.Name, err)
374368
}
375369
glog.V(4).Infof("Build %s/%s status was updated %s -> %s", build.Namespace, build.Name, build.Status.Phase, nextStatus)
370+
371+
runPolicy := policy.ForBuild(build, bc.RunPolicies)
372+
if runPolicy == nil {
373+
glog.Errorf("unable to determine build scheduler for %s/%s", build.Namespace, build.Name)
374+
return nil
375+
}
376+
if buildutil.IsBuildComplete(build) {
377+
if err := runPolicy.OnComplete(build); err != nil {
378+
glog.Errorf("failed to run policy on completed build: %v", err)
379+
}
380+
}
376381
}
377382
return nil
378383
}

pkg/build/controller/factory/factory.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ func (factory *BuildControllerFactory) CreateDeleteController() controller.Runna
171171
type BuildPodControllerFactory struct {
172172
OSClient osclient.Interface
173173
KubeClient kclientset.Interface
174+
BuildLister buildclient.BuildLister
174175
BuildUpdater buildclient.BuildUpdater
175176
// Stop may be set to allow controllers created by this factory to be terminated.
176177
Stop <-chan struct{}
@@ -214,6 +215,7 @@ func (factory *BuildPodControllerFactory) Create() controller.RunnableController
214215
BuildUpdater: factory.BuildUpdater,
215216
SecretClient: factory.KubeClient.Core(),
216217
PodManager: client,
218+
RunPolicies: policy.GetAllRunPolicies(factory.BuildLister, factory.BuildUpdater),
217219
}
218220

219221
return &controller.RetryController{

pkg/build/controller/policy/policy.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import (
55
"time"
66

77
"github.com/golang/glog"
8+
"github.com/pborman/uuid"
9+
"k8s.io/kubernetes/pkg/api/errors"
10+
"k8s.io/kubernetes/pkg/util/wait"
11+
812
buildapi "github.com/openshift/origin/pkg/build/api"
913
buildclient "github.com/openshift/origin/pkg/build/client"
1014
buildutil "github.com/openshift/origin/pkg/build/util"
11-
"k8s.io/kubernetes/pkg/api/errors"
12-
"k8s.io/kubernetes/pkg/api/unversioned"
13-
"k8s.io/kubernetes/pkg/util/wait"
1415
)
1516

1617
// RunPolicy is an interface that define handler for the build runPolicy field.
@@ -124,7 +125,7 @@ func GetNextConfigBuild(lister buildclient.BuildLister, namespace, buildConfigNa
124125
}
125126

126127
// handleComplete represents the default OnComplete handler. This Handler will
127-
// check which build should be run next and update the StartTimestamp field for
128+
// check which build should be run next and set the accepted annotation for
128129
// that build. That will trigger HandleBuild() to process that build immediately
129130
// and as a result the build is immediately executed.
130131
func handleComplete(lister buildclient.BuildLister, updater buildclient.BuildUpdater, build *buildapi.Build) error {
@@ -139,9 +140,9 @@ func handleComplete(lister buildclient.BuildLister, updater buildclient.BuildUpd
139140
if hasRunningBuilds || len(nextBuilds) == 0 {
140141
return nil
141142
}
142-
now := unversioned.Now()
143143
for _, build := range nextBuilds {
144-
build.Status.StartTimestamp = &now
144+
// TODO: replace with informer notification requeueing in the future
145+
build.Annotations[buildapi.BuildAcceptedAnnotation] = uuid.NewRandom().String()
145146
err := wait.Poll(500*time.Millisecond, 5*time.Second, func() (bool, error) {
146147
err := updater.Update(build.Namespace, build)
147148
if err != nil && errors.IsConflict(err) {

pkg/build/controller/policy/policy_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,12 @@ func TestHandleCompleteSerial(t *testing.T) {
112112
t.Errorf("unexpected error: %v", err)
113113
}
114114

115-
if resultBuilds.Items[1].Status.StartTimestamp == nil {
116-
t.Errorf("build-2 should have Status.StartTimestamp set to trigger it")
115+
if _, ok := resultBuilds.Items[1].Annotations[buildapi.BuildAcceptedAnnotation]; !ok {
116+
t.Errorf("build-2 should have Annotation %s set to trigger it", buildapi.BuildAcceptedAnnotation)
117117
}
118118

119-
if resultBuilds.Items[2].Status.StartTimestamp != nil {
120-
t.Errorf("build-3 should not have Status.StartTimestamp set")
119+
if _, ok := resultBuilds.Items[2].Annotations[buildapi.BuildAcceptedAnnotation]; ok {
120+
t.Errorf("build-3 should not have Annotation %s set", buildapi.BuildAcceptedAnnotation)
121121
}
122122
}
123123

@@ -139,11 +139,11 @@ func TestHandleCompleteParallel(t *testing.T) {
139139
t.Errorf("unexpected error: %v", err)
140140
}
141141

142-
if resultBuilds.Items[1].Status.StartTimestamp == nil {
143-
t.Errorf("build-2 should have Status.StartTimestamp set to trigger it")
142+
if _, ok := resultBuilds.Items[1].Annotations[buildapi.BuildAcceptedAnnotation]; !ok {
143+
t.Errorf("build-2 should have Annotation %s set to trigger it", buildapi.BuildAcceptedAnnotation)
144144
}
145145

146-
if resultBuilds.Items[2].Status.StartTimestamp == nil {
147-
t.Errorf("build-3 should have Status.StartTimestamp set to trigger it")
146+
if _, ok := resultBuilds.Items[2].Annotations[buildapi.BuildAcceptedAnnotation]; !ok {
147+
t.Errorf("build-3 should have Annotation %s set to trigger it", buildapi.BuildAcceptedAnnotation)
148148
}
149149
}

pkg/cmd/server/origin/run_components.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ func (c *MasterConfig) RunBuildPodController() {
293293
OSClient: osclient,
294294
KubeClient: kclient,
295295
BuildUpdater: buildclient.NewOSClientBuildClient(osclient),
296+
BuildLister: buildclient.NewOSClientBuildClient(osclient),
296297
}
297298
controller := factory.Create()
298299
controller.Run()

0 commit comments

Comments
 (0)