Skip to content

Commit 61545df

Browse files
authored
Merge pull request #4525 from greedy-wudpeckr/Fixed-ignored-error-handling
backend: Fixed ignored k8cache error handling
2 parents 97f4122 + 20c051c commit 61545df

File tree

1 file changed

+57
-40
lines changed

1 file changed

+57
-40
lines changed

backend/cmd/server.go

Lines changed: 57 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,21 @@ func GetContextKeyAndKContext(w http.ResponseWriter,
183183
return ctx, span, contextKey, kContext, nil
184184
}
185185

186-
// handleCacheRequest processes a request with caching logic.
187-
func handleCacheRequest(c *HeadlampConfig, next http.Handler, w http.ResponseWriter, r *http.Request) {
186+
// CacheMiddleWare is middleware for caching purposes. It generates a key for each request,
187+
// authorizes the user, stores resource data in cache, and returns cached data when available.
188+
func CacheMiddleWare(c *HeadlampConfig) mux.MiddlewareFunc {
189+
return func(next http.Handler) http.Handler {
190+
if !c.CacheEnabled {
191+
return next
192+
}
193+
194+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
195+
cacheMiddlewareHandler(c, next, w, r)
196+
})
197+
}
198+
}
199+
200+
func cacheMiddlewareHandler(c *HeadlampConfig, next http.Handler, w http.ResponseWriter, r *http.Request) {
188201
if k8cache.SkipWebSocket(r, next, w) {
189202
return
190203
}
@@ -195,14 +208,8 @@ func handleCacheRequest(c *HeadlampConfig, next http.Handler, w http.ResponseWri
195208
}
196209

197210
if err := k8cache.HandleNonGETCacheInvalidation(k8sResponseCache, w, r, next, contextKey); err != nil {
198-
// ErrHandled is a sentinel error indicating the request was fully
199-
// processed during cache invalidation. For non-GET requests
200-
// (POST/PUT/DELETE), HandleNonGETCacheInvalidation invalidates the
201-
// cache, makes a fresh request to K8s, stores the response, and
202-
// writes the response to the client. When ErrHandled is returned,
203-
// the request has already been handled and we must return early to
204-
// avoid processing the request again or writing duplicate responses.
205211
if errors.Is(err, k8cache.ErrHandled) {
212+
// Request was already handled (response written), return early
206213
return
207214
}
208215

@@ -215,55 +222,65 @@ func handleCacheRequest(c *HeadlampConfig, next http.Handler, w http.ResponseWri
215222

216223
key, err := k8cache.GenerateKey(r.URL, contextKey)
217224
if err != nil {
218-
c.handleError(w, ctx, span, err, "failed to generate key ", http.StatusBadRequest)
225+
c.handleError(w, ctx, span, err, "failed to generate key", http.StatusBadRequest)
219226
return
220227
}
221228

229+
handled := handleCacheAuthorization(c, next, w, r, rcw, ctx, span, contextKey, kContext, key)
230+
if handled {
231+
return
232+
}
233+
234+
k8cache.CheckForChanges(k8sResponseCache, contextKey, *kContext)
235+
236+
next.ServeHTTP(rcw, r)
237+
238+
if err := k8cache.StoreK8sResponseInCache(k8sResponseCache, r.URL, rcw, r, key); err != nil {
239+
// Response was already written to client via rcw; just log the cache storage error
240+
logger.Log(logger.LevelError, nil, err, "failed to store response in cache")
241+
}
242+
}
243+
244+
func handleCacheAuthorization(
245+
c *HeadlampConfig,
246+
next http.Handler,
247+
w http.ResponseWriter,
248+
r *http.Request,
249+
rcw *k8cache.ResponseCapture,
250+
ctx context.Context,
251+
span trace.Span,
252+
contextKey string,
253+
kContext *kubeconfig.Context,
254+
key string,
255+
) bool {
222256
isAllowed, authErr := k8cache.IsAllowed(kContext, r)
223257
if authErr != nil {
224258
k8cache.ServeFromCacheOrForwardToK8s(k8sResponseCache, isAllowed, next, key, w, r, rcw)
225259

226-
return
227-
} else if !isAllowed && k8cache.IsAuthBypassURL(r.URL.Path) {
228-
_ = k8cache.ReturnAuthErrorResponse(w, r, contextKey)
260+
return true
261+
}
229262

230-
return
263+
if !isAllowed && k8cache.IsAuthBypassURL(r.URL.Path) {
264+
if err := k8cache.ReturnAuthErrorResponse(w, r, contextKey); err != nil {
265+
c.handleError(w, ctx, span, err, "failed to return auth error response", http.StatusInternalServerError)
266+
}
267+
268+
return true
231269
}
232270

233271
served, err := k8cache.LoadFromCache(k8sResponseCache, isAllowed, key, w, r)
234272
if err != nil {
235-
c.handleError(w, ctx, span, errors.New(kContext.Error), "failed to load from cache", http.StatusServiceUnavailable)
236-
return
273+
// Cache read failed; log error and fall back to K8s instead of failing the request
274+
logger.Log(logger.LevelError, nil, err, "failed to load from cache")
275+
return false
237276
}
238277

239278
if served {
240279
c.TelemetryHandler.RecordEvent(span, "Served from cache")
241-
return
280+
return true
242281
}
243282

244-
k8cache.CheckForChanges(k8sResponseCache, contextKey, *kContext)
245-
246-
next.ServeHTTP(rcw, r)
247-
248-
err = k8cache.StoreK8sResponseInCache(k8sResponseCache, r.URL, rcw, r, key)
249-
if err != nil {
250-
c.handleError(w, ctx, span, errors.New(kContext.Error), "error while storing into cache", http.StatusBadRequest)
251-
return
252-
}
253-
}
254-
255-
// CacheMiddleWare is Middleware for Caching purpose. It involves generating key for a request,
256-
// authorizing user , store resource data in cache and returns data if key is present.
257-
func CacheMiddleWare(c *HeadlampConfig) mux.MiddlewareFunc {
258-
return func(next http.Handler) http.Handler {
259-
if !c.CacheEnabled {
260-
return next
261-
}
262-
263-
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
264-
handleCacheRequest(c, next, w, r)
265-
})
266-
}
283+
return false
267284
}
268285

269286
func runListPlugins() {

0 commit comments

Comments
 (0)