66 "fmt"
77 "html/template"
88 "net/http"
9+ "sync"
910 "time"
1011
1112 "github.com/kedacore/http-add-on/operator/apis/http/v1alpha1"
@@ -76,11 +77,19 @@ const defaultPlaceholderTemplate = `<!DOCTYPE html>
7677</body>
7778</html>`
7879
80+ // cacheEntry stores a template along with resource generation info for cache invalidation
81+ type cacheEntry struct {
82+ template * template.Template
83+ hsoGeneration int64
84+ configMapVersion string
85+ }
86+
7987// PlaceholderHandler handles serving placeholder pages during scale-from-zero
8088type PlaceholderHandler struct {
8189 k8sClient kubernetes.Interface
8290 routingTable routing.Table
83- templateCache map [string ]* template.Template
91+ templateCache map [string ]* cacheEntry
92+ cacheMutex sync.RWMutex
8493 defaultTmpl * template.Template
8594}
8695
@@ -103,7 +112,7 @@ func NewPlaceholderHandler(k8sClient kubernetes.Interface, routingTable routing.
103112 return & PlaceholderHandler {
104113 k8sClient : k8sClient ,
105114 routingTable : routingTable ,
106- templateCache : make (map [string ]* template. Template ),
115+ templateCache : make (map [string ]* cacheEntry ),
107116 defaultTmpl : defaultTmpl ,
108117 }, nil
109118}
@@ -165,29 +174,45 @@ func (h *PlaceholderHandler) getTemplate(ctx context.Context, hso *v1alpha1.HTTP
165174
166175 if config .Content != "" {
167176 cacheKey := fmt .Sprintf ("%s/%s/inline" , hso .Namespace , hso .Name )
168- if tmpl , ok := h .templateCache [cacheKey ]; ok {
169- return tmpl , nil
177+
178+ h .cacheMutex .RLock ()
179+ entry , ok := h .templateCache [cacheKey ]
180+ if ok && entry .hsoGeneration == hso .Generation {
181+ h .cacheMutex .RUnlock ()
182+ return entry .template , nil
170183 }
184+ h .cacheMutex .RUnlock ()
171185
172186 tmpl , err := template .New ("inline" ).Parse (config .Content )
173187 if err != nil {
174188 return nil , err
175189 }
176- h .templateCache [cacheKey ] = tmpl
190+
191+ h .cacheMutex .Lock ()
192+ h .templateCache [cacheKey ] = & cacheEntry {
193+ template : tmpl ,
194+ hsoGeneration : hso .Generation ,
195+ }
196+ h .cacheMutex .Unlock ()
177197 return tmpl , nil
178198 }
179199
180200 if config .ContentConfigMap != "" {
181201 cacheKey := fmt .Sprintf ("%s/%s/cm/%s" , hso .Namespace , hso .Name , config .ContentConfigMap )
182- if tmpl , ok := h .templateCache [cacheKey ]; ok {
183- return tmpl , nil
184- }
185202
186203 cm , err := h .k8sClient .CoreV1 ().ConfigMaps (hso .Namespace ).Get (ctx , config .ContentConfigMap , metav1.GetOptions {})
187204 if err != nil {
188205 return nil , fmt .Errorf ("failed to get ConfigMap %s: %w" , config .ContentConfigMap , err )
189206 }
190207
208+ h .cacheMutex .RLock ()
209+ entry , ok := h .templateCache [cacheKey ]
210+ if ok && entry .hsoGeneration == hso .Generation && entry .configMapVersion == cm .ResourceVersion {
211+ h .cacheMutex .RUnlock ()
212+ return entry .template , nil
213+ }
214+ h .cacheMutex .RUnlock ()
215+
191216 key := config .ContentConfigMapKey
192217 if key == "" {
193218 key = "template.html"
@@ -202,7 +227,14 @@ func (h *PlaceholderHandler) getTemplate(ctx context.Context, hso *v1alpha1.HTTP
202227 if err != nil {
203228 return nil , err
204229 }
205- h .templateCache [cacheKey ] = tmpl
230+
231+ h .cacheMutex .Lock ()
232+ h .templateCache [cacheKey ] = & cacheEntry {
233+ template : tmpl ,
234+ hsoGeneration : hso .Generation ,
235+ configMapVersion : cm .ResourceVersion ,
236+ }
237+ h .cacheMutex .Unlock ()
206238 return tmpl , nil
207239 }
208240
0 commit comments