This is an automated email from the ASF dual-hosted git repository.

wilfred-s pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/yunikorn-k8shim.git


The following commit(s) were added to refs/heads/master by this push:
     new 0baa5ea3 [YUNIKORN-3371] DRA resource-slice tracker goroutine leaks in 
tests (#1087)
0baa5ea3 is described below

commit 0baa5ea33387f31413dfb9b4e81ca8b79276f831
Author: PoiBlackTea <[email protected]>
AuthorDate: Thu Sep 10 21:02:29 2026 +1000

    [YUNIKORN-3371] DRA resource-slice tracker goroutine leaks in tests (#1087)
    
    - Save resourceSliceTracker in Context and add Context.Stop() to shut down
      the tracker
    - Call Context.Stop() in KubernetesShim.Stop()
    - Disable EnableDeviceTaintRules in support.SharedDRAManager() to prevent
      goroutine leaks in mock tests
    - Add TestContextStop unit test
    
    Signed-off-by: PoiBlackTea <[email protected]>
    
    Closes: #1087
    
    Signed-off-by: Wilfred Spiegelenburg <[email protected]>
---
 pkg/cache/context.go               | 32 +++++++++++++++++++++++---------
 pkg/cache/context_test.go          |  8 ++++++++
 pkg/plugin/support/mock_helpers.go |  7 ++++++-
 pkg/shim/scheduler.go              |  4 ++++
 4 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/pkg/cache/context.go b/pkg/cache/context.go
index e0878250..6e7e2fec 100644
--- a/pkg/cache/context.go
+++ b/pkg/cache/context.go
@@ -72,15 +72,16 @@ var (
 
 // context maintains scheduling state, like apps and apps' tasks.
 type Context struct {
-       applications   map[string]*Application        // apps
-       schedulerCache *schedulercache.SchedulerCache // external cache
-       apiProvider    client.APIProvider             // apis to interact with 
api-server, scheduler-core, etc
-       predManager    predicates.PredicateManager    // K8s predicates
-       namespace      string                         // yunikorn namespace
-       configMaps     []*v1.ConfigMap                // cached yunikorn 
configmaps
-       lock           *locking.RWMutex               // lock - used not only 
for context data but also to ensure that multiple event types are not executed 
concurrently
-       txnID          atomic.Uint64                  // transaction ID counter
-       klogger        klog.Logger
+       applications         map[string]*Application        // apps
+       schedulerCache       *schedulercache.SchedulerCache // external cache
+       apiProvider          client.APIProvider             // apis to interact 
with api-server, scheduler-core, etc
+       predManager          predicates.PredicateManager    // K8s predicates
+       namespace            string                         // yunikorn 
namespace
+       configMaps           []*v1.ConfigMap                // cached yunikorn 
configmaps
+       lock                 *locking.RWMutex               // lock - used not 
only for context data but also to ensure that multiple event types are not 
executed concurrently
+       txnID                atomic.Uint64                  // transaction ID 
counter
+       klogger              klog.Logger
+       resourceSliceTracker *tracker.Tracker
 }
 
 // NewContext create a new context for the scheduler using a default (empty) 
configuration
@@ -127,6 +128,7 @@ func NewContextWithBootstrapConfigMaps(apis 
client.APIProvider, bootstrapConfigM
                        log.Log(log.ShimClient).Error("unable to create the 
resource slice tracker", zap.Error(err))
                        return nil
                }
+               ctx.resourceSliceTracker = resourceSliceTracker
                sharedDRAManager = 
dynamicresources.NewDRAManager(context.TODO(), resourceClaimCache, 
resourceSliceTracker, informerFactory)
        }
 
@@ -138,6 +140,18 @@ func NewContextWithBootstrapConfigMaps(apis 
client.APIProvider, bootstrapConfigM
        return ctx
 }
 
+// Stop ends all background activity managed by Context.
+func (ctx *Context) Stop() {
+       ctx.lock.Lock()
+       t := ctx.resourceSliceTracker
+       ctx.resourceSliceTracker = nil
+       ctx.lock.Unlock()
+
+       if t != nil {
+               t.Stop()
+       }
+}
+
 func (ctx *Context) AddSchedulingEventHandlers() error {
        err := ctx.apiProvider.AddEventHandler(&client.ResourceEventHandlers{
                Type:     client.ConfigMapInformerHandlers,
diff --git a/pkg/cache/context_test.go b/pkg/cache/context_test.go
index 07a534d2..787b76c8 100644
--- a/pkg/cache/context_test.go
+++ b/pkg/cache/context_test.go
@@ -2770,3 +2770,11 @@ func TestTerminatedOrphanedForeignPodNotAdopted(t 
*testing.T) {
                })
        }
 }
+
+func TestContextStop(t *testing.T) {
+       context := NewContext(client.NewMockedAPIProvider(false))
+       assert.Assert(t, context.resourceSliceTracker != nil)
+
+       context.Stop()
+       assert.Assert(t, context.resourceSliceTracker == nil)
+}
diff --git a/pkg/plugin/support/mock_helpers.go 
b/pkg/plugin/support/mock_helpers.go
index 0d74eb3a..4ed16545 100644
--- a/pkg/plugin/support/mock_helpers.go
+++ b/pkg/plugin/support/mock_helpers.go
@@ -50,8 +50,13 @@ func SharedDRAManager() *dynamicresources.DefaultDRAManager {
        if 
feature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation) {
                resourceClaimInformer := 
InformerFactory(ClientSet()).Resource().V1().ResourceClaims().Informer()
                resourceClaimCache := 
assumecache.NewAssumeCache(klog.NewKlogr(), resourceClaimInformer, 
"ResourceClaim", "", nil)
+               // Disable device taint rules in mock helper to prevent 
goroutine leaks in tests.
+               // When EnableDeviceTaintRules is true, tracker.StartTracker 
spawns a background goroutine waiting
+               // for informers to sync, which leaks because unit test 
informers never sync. Existing unit tests
+               // do not exercise device taints or DRA resources. If future 
tests specifically require device taint
+               // tracking, this should be re-enabled along with a proper 
shutdown lifecycle.
                resourceSliceTracker, err := 
tracker.StartTracker(context.TODO(), tracker.Options{
-                       EnableDeviceTaintRules: 
feature.DefaultFeatureGate.Enabled(features.DRADeviceTaints),
+                       EnableDeviceTaintRules: false,
                        SliceInformer:          
InformerFactory(ClientSet()).Resource().V1().ResourceSlices(),
                        ClassInformer:          
InformerFactory(ClientSet()).Resource().V1().DeviceClasses(),
                        TaintInformer:          
InformerFactory(ClientSet()).Resource().V1beta2().DeviceTaintRules()})
diff --git a/pkg/shim/scheduler.go b/pkg/shim/scheduler.go
index 3d55070a..9a640250 100644
--- a/pkg/shim/scheduler.go
+++ b/pkg/shim/scheduler.go
@@ -252,6 +252,10 @@ func (ss *KubernetesShim) Stop() {
                ss.phManager.Stop()
                // stop the dispatcher
                dispatcher.Stop()
+               // stop the context
+               if ss.context != nil {
+                       ss.context.Stop()
+               }
        })
        if !stopped {
                log.Log(log.ShimScheduler).Info("scheduler is already stopped")


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to