@@ -120,6 +120,11 @@ type sharedInformerFactory struct {
120
120
// startedInformers is used for tracking which informers have been started.
121
121
// This allows Start() to be called multiple times safely.
122
122
startedInformers map[reflect.Type]bool
123
+ // wg tracks how many goroutines were started.
124
+ wg sync.WaitGroup
125
+ // shuttingDown is true when Shutdown has been called. It may still be running
126
+ // because it needs to wait for goroutines.
127
+ shuttingDown bool
123
128
}
124
129
125
130
// WithCustomResyncConfig sets a custom resync period for the specified informer types.
@@ -173,15 +178,36 @@ func NewSharedInformerFactoryWithOptions(client clientset.ClusterInterface, defa
173
178
174
179
// Start initializes all requested informers.
175
180
func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
176
- f.lock.Lock()
177
- defer f.lock.Unlock()
181
+ f.lock.Lock()
182
+ defer f.lock.Unlock()
178
183
179
- for informerType, informer := range f.informers {
180
- if !f.startedInformers[informerType] {
181
- go informer.Run(stopCh)
182
- f.startedInformers[informerType] = true
183
- }
184
- }
184
+ if f.shuttingDown {
185
+ return
186
+ }
187
+
188
+ for informerType, informer := range f.informers {
189
+ if !f.startedInformers[informerType] {
190
+ f.wg.Add(1)
191
+ // We need a new variable in each loop iteration,
192
+ // otherwise the goroutine would use the loop variable
193
+ // and that keeps changing.
194
+ informer := informer
195
+ go func() {
196
+ defer f.wg.Done()
197
+ informer.Run(stopCh)
198
+ }()
199
+ f.startedInformers[informerType] = true
200
+ }
201
+ }
202
+ }
203
+
204
+ func (f *sharedInformerFactory) Shutdown() {
205
+ f.lock.Lock()
206
+ f.shuttingDown = true
207
+ f.lock.Unlock()
208
+
209
+ // Will return immediately if there is nothing to wait for.
210
+ f.wg.Wait()
185
211
}
186
212
187
213
// WaitForCacheSync waits for all started informers' cache were synced.
@@ -206,8 +232,7 @@ func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[ref
206
232
return res
207
233
}
208
234
209
- // InformerFor returns the SharedIndexInformer for obj using an internal
210
- // client.
235
+ // InformerFor returns the SharedIndexInformer for obj.
211
236
func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) kcpcache.ScopeableSharedIndexInformer {
212
237
f.lock.Lock()
213
238
defer f.lock.Unlock()
@@ -230,18 +255,69 @@ func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internal
230
255
}
231
256
232
257
type ScopedDynamicSharedInformerFactory interface {
258
+ // ForResource gives generic access to a shared informer of the matching type.
233
259
ForResource(resource schema.GroupVersionResource) ({{if .useUpstreamInterfaces}}upstreaminformers.{{end}}GenericInformer, error)
260
+
261
+ // Start initializes all requested informers. They are handled in goroutines
262
+ // which run until the stop channel gets closed.
234
263
Start(stopCh <-chan struct{})
235
264
}
236
265
237
266
// SharedInformerFactory provides shared informers for resources in all known
238
267
// API group versions.
268
+ //
269
+ // It is typically used like this:
270
+ //
271
+ // ctx, cancel := context.Background()
272
+ // defer cancel()
273
+ // factory := NewSharedInformerFactoryWithOptions(client, resyncPeriod)
274
+ // defer factory.Shutdown() // Returns immediately if nothing was started.
275
+ // genericInformer := factory.ForResource(resource)
276
+ // typedInformer := factory.SomeAPIGroup().V1().SomeType()
277
+ // factory.Start(ctx.Done()) // Start processing these informers.
278
+ // synced := factory.WaitForCacheSync(ctx.Done())
279
+ // for v, ok := range synced {
280
+ // if !ok {
281
+ // fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v)
282
+ // return
283
+ // }
284
+ // }
285
+ //
286
+ // // Creating informers can also be created after Start, but then
287
+ // // Start must be called again:
288
+ // anotherGenericInformer := factory.ForResource(resource)
289
+ // factory.Start(ctx.Done())
239
290
type SharedInformerFactory interface {
240
291
internalinterfaces.SharedInformerFactory
292
+
241
293
Cluster(logicalcluster.Name) ScopedDynamicSharedInformerFactory
294
+
295
+ // Start initializes all requested informers. They are handled in goroutines
296
+ // which run until the stop channel gets closed.
297
+ Start(stopCh <-chan struct{})
298
+
299
+ // Shutdown marks a factory as shutting down. At that point no new
300
+ // informers can be started anymore and Start will return without
301
+ // doing anything.
302
+ //
303
+ // In addition, Shutdown blocks until all goroutines have terminated. For that
304
+ // to happen, the close channel(s) that they were started with must be closed,
305
+ // either before Shutdown gets called or while it is waiting.
306
+ //
307
+ // Shutdown may be called multiple times, even concurrently. All such calls will
308
+ // block until all goroutines have terminated.
309
+ Shutdown()
310
+
311
+ // ForResource gives generic access to a shared informer of the matching type.
242
312
ForResource(resource schema.GroupVersionResource) (GenericClusterInformer, error)
313
+
314
+ // WaitForCacheSync blocks until all started informers' caches were synced
315
+ // or the stop channel gets closed.
243
316
WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
244
317
318
+ // InformerFor returns the SharedIndexInformer for obj.
319
+ InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) kcpcache.ScopeableSharedIndexInformer
320
+
245
321
{{range .groups}} {{.GoName}}() {{.Group.PackageName}}informers.ClusterInterface
246
322
{{end -}}
247
323
}
@@ -366,8 +442,7 @@ func (f *sharedScopedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) m
366
442
return res
367
443
}
368
444
369
- // InformerFor returns the SharedIndexInformer for obj using an internal
370
- // client.
445
+ // InformerFor returns the SharedIndexInformer for obj.
371
446
func (f *sharedScopedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewScopedInformerFunc) cache.SharedIndexInformer {
372
447
f.lock.Lock()
373
448
defer f.lock.Unlock()
0 commit comments