Skip to content

Commit f73674e

Browse files
committed
wait for cache start before returning from WaitForCacheSync
There is currently an unintuitive race condition between starting a cache, waiting for it to sync, and using it the first time. The crux of the problem is that WaitForCacheSync can return true BEFORE the Start function has had a chance to set started to true. This means that Get and List can return ErrCacheNotStarted even after WaitForCacheSync has returned true. This commit adds a channel and a wait function that is called from WaitForCacheSync to ensure that started has been set to true before returning.
1 parent 8022402 commit f73674e

File tree

2 files changed

+21
-0
lines changed

2 files changed

+21
-0
lines changed

pkg/cache/internal/deleg_map.go

+6
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ func (m *InformersMap) WaitForCacheSync(stop <-chan struct{}) bool {
6868
syncedFuncs := append([]cache.InformerSynced(nil), m.structured.HasSyncedFuncs()...)
6969
syncedFuncs = append(syncedFuncs, m.unstructured.HasSyncedFuncs()...)
7070

71+
if !m.structured.waitForStarted(stop) {
72+
return false
73+
}
74+
if !m.unstructured.waitForStarted(stop) {
75+
return false
76+
}
7177
return cache.WaitForCacheSync(stop, syncedFuncs...)
7278
}
7379

pkg/cache/internal/informers_map.go

+15
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ func newSpecificInformersMap(config *rest.Config,
5454
codecs: serializer.NewCodecFactory(scheme),
5555
paramCodec: runtime.NewParameterCodec(scheme),
5656
resync: resync,
57+
startWait: make(chan struct{}),
5758
createListWatcher: createListWatcher,
5859
namespace: namespace,
5960
}
@@ -104,6 +105,10 @@ type specificInformersMap struct {
104105
// start is true if the informers have been started
105106
started bool
106107

108+
// startWait is a channel that is closed after the
109+
// informer has been started.
110+
startWait chan struct{}
111+
107112
// createClient knows how to create a client and a list object,
108113
// and allows for abstracting over the particulars of structured vs
109114
// unstructured objects.
@@ -131,10 +136,20 @@ func (ip *specificInformersMap) Start(stop <-chan struct{}) {
131136

132137
// Set started to true so we immediately start any informers added later.
133138
ip.started = true
139+
close(ip.startWait)
134140
}()
135141
<-stop
136142
}
137143

144+
func (ip *specificInformersMap) waitForStarted(stop <-chan struct{}) bool {
145+
select {
146+
case <-ip.startWait:
147+
return true
148+
case <-stop:
149+
return false
150+
}
151+
}
152+
138153
// HasSyncedFuncs returns all the HasSynced functions for the informers in this map.
139154
func (ip *specificInformersMap) HasSyncedFuncs() []cache.InformerSynced {
140155
ip.mu.RLock()

0 commit comments

Comments
 (0)