Skip to content

Commit 79e7414

Browse files
committed
controller/factory: Avoid adding the same informer more than once
Adding the same informer several times is useless and has a negative side-effect: a change of object on API-server leads to scheduling reconcile loop several times. Calling reconcile more often than necessary is not great.
1 parent ac3ba9e commit 79e7414

File tree

2 files changed

+40
-3
lines changed

2 files changed

+40
-3
lines changed

pkg/controller/factory/factory.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ package factory
33
import (
44
"context"
55
"fmt"
6+
"reflect"
67
"time"
78

89
"github.com/robfig/cron"
910
"k8s.io/apimachinery/pkg/runtime"
1011
errorutil "k8s.io/apimachinery/pkg/util/errors"
12+
"k8s.io/apimachinery/pkg/util/sets"
1113
"k8s.io/client-go/tools/cache"
1214

1315
"github.com/openshift/library-go/pkg/operator/events"
@@ -245,6 +247,11 @@ func (f *Factory) WithControllerInstanceName(controllerInstanceName string) *Fac
245247
return f
246248
}
247249

250+
type informerHandleTuple struct {
251+
informer Informer
252+
filter uintptr
253+
}
254+
248255
// Controller produce a runnable controller.
249256
func (f *Factory) ToController(name string, eventRecorder events.Recorder) Controller {
250257
if f.sync == nil {
@@ -286,19 +293,37 @@ func (f *Factory) ToController(name string, eventRecorder events.Recorder) Contr
286293
cacheSyncTimeout: defaultCacheSyncTimeout,
287294
}
288295

296+
// avoid adding an informer more than once
297+
informerQueueKeySet := sets.New[informerHandleTuple]()
289298
for i := range f.informerQueueKeys {
290299
for d := range f.informerQueueKeys[i].informers {
291300
informer := f.informerQueueKeys[i].informers[d]
292301
queueKeyFn := f.informerQueueKeys[i].queueKeyFn
293-
informer.AddEventHandler(c.syncContext.(syncContext).eventHandler(queueKeyFn, f.informerQueueKeys[i].filter))
302+
tuple := informerHandleTuple{
303+
informer: informer,
304+
filter: reflect.ValueOf(f.informerQueueKeys[i].filter).Pointer(),
305+
}
306+
if !informerQueueKeySet.Has(tuple) {
307+
sets.Insert(informerQueueKeySet, tuple)
308+
informer.AddEventHandler(c.syncContext.(syncContext).eventHandler(queueKeyFn, f.informerQueueKeys[i].filter))
309+
}
294310
c.cachesToSync = append(c.cachesToSync, informer.HasSynced)
295311
}
296312
}
297313

314+
// avoid adding an informer more than once
315+
informerSet := sets.New[informerHandleTuple]()
298316
for i := range f.informers {
299317
for d := range f.informers[i].informers {
300318
informer := f.informers[i].informers[d]
301-
informer.AddEventHandler(c.syncContext.(syncContext).eventHandler(DefaultQueueKeysFunc, f.informers[i].filter))
319+
tuple := informerHandleTuple{
320+
informer: informer,
321+
filter: reflect.ValueOf(f.informers[i].filter).Pointer(),
322+
}
323+
if !informerSet.Has(tuple) {
324+
sets.Insert(informerSet, tuple)
325+
informer.AddEventHandler(c.syncContext.(syncContext).eventHandler(DefaultQueueKeysFunc, f.informers[i].filter))
326+
}
302327
c.cachesToSync = append(c.cachesToSync, informer.HasSynced)
303328
}
304329
}

pkg/controller/factory/factory_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,17 @@ func TestMultiWorkerControllerShutdown(t *testing.T) {
174174
workersShutdownMutex.Unlock()
175175
}
176176

177-
func TestControllerWithInformer(t *testing.T) {
177+
func testControllerWithInformer(t *testing.T, once bool) {
178178
kubeClient := fake.NewSimpleClientset()
179179

180180
kubeInformers := informers.NewSharedInformerFactoryWithOptions(kubeClient, 10*time.Second, informers.WithNamespace("test"))
181181
ctx, cancel := context.WithCancel(context.TODO())
182182
go kubeInformers.Core().V1().Secrets().Informer().Run(ctx.Done())
183183

184184
factory := New().WithInformers(kubeInformers.Core().V1().Secrets().Informer())
185+
if !once {
186+
factory = factory.WithInformers(kubeInformers.Core().V1().Secrets().Informer())
187+
}
185188

186189
controllerSynced := make(chan struct{})
187190
controller := factory.WithSync(func(ctx context.Context, syncContext SyncContext) error {
@@ -210,6 +213,15 @@ func TestControllerWithInformer(t *testing.T) {
210213
}
211214
}
212215

216+
func TestControllerWithInformer(t *testing.T) {
217+
testControllerWithInformer(t, true)
218+
}
219+
220+
// The same as above, but registers the same informer twice (OCPBUGS-54385)
221+
func TestControllerWithInformer2(t *testing.T) {
222+
testControllerWithInformer(t, false)
223+
}
224+
213225
func TestControllerScheduled(t *testing.T) {
214226
syncCalled := make(chan struct{})
215227
controller := New().ResyncSchedule("@every 1s").WithSync(func(ctx context.Context, controllerContext SyncContext) error {

0 commit comments

Comments
 (0)