@@ -41,6 +41,7 @@ import (
41
41
"k8s.io/apiserver/pkg/endpoints/request"
42
42
"k8s.io/apiserver/pkg/features"
43
43
"k8s.io/apiserver/pkg/registry/rest"
44
+ genericfilters "k8s.io/apiserver/pkg/server/filters"
44
45
utilfeature "k8s.io/apiserver/pkg/util/feature"
45
46
"k8s.io/component-base/tracing"
46
47
"k8s.io/klog/v2"
@@ -259,7 +260,7 @@ func ListResource(r rest.Lister, rw rest.Watcher, scope *RequestScope, forceWatc
259
260
}
260
261
klog .V (3 ).InfoS ("Starting watch" , "path" , req .URL .Path , "resourceVersion" , opts .ResourceVersion , "labels" , opts .LabelSelector , "fields" , opts .FieldSelector , "timeout" , timeout )
261
262
ctx , cancel := context .WithTimeout (ctx , timeout )
262
- defer cancel ()
263
+ defer func () { cancel () } ()
263
264
watcher , err := rw .Watch (ctx , & opts )
264
265
if err != nil {
265
266
scope .err (err , w , req )
@@ -270,11 +271,26 @@ func ListResource(r rest.Lister, rw rest.Watcher, scope *RequestScope, forceWatc
270
271
scope .err (err , w , req )
271
272
return
272
273
}
273
- requestInfo , _ := request .RequestInfoFrom (ctx )
274
- metrics .RecordLongRunning (req , requestInfo , metrics .APIServerComponent , func () {
275
- defer watcher .Stop ()
276
- handler .ServeHTTP (w , req )
277
- })
274
+ // Invalidate cancel() to defer until serve() is complete.
275
+ deferredCancel := cancel
276
+ cancel = func () {}
277
+
278
+ serve := func () {
279
+ defer deferredCancel ()
280
+ requestInfo , _ := request .RequestInfoFrom (ctx )
281
+ metrics .RecordLongRunning (req , requestInfo , metrics .APIServerComponent , func () {
282
+ defer watcher .Stop ()
283
+ handler .ServeHTTP (w , req )
284
+ })
285
+ }
286
+
287
+ // Run watch serving in a separate goroutine to allow freeing current stack memory
288
+ t := genericfilters .TaskFrom (req .Context ())
289
+ if t != nil {
290
+ t .Func = serve
291
+ } else {
292
+ serve ()
293
+ }
278
294
return
279
295
}
280
296
0 commit comments