github.com/kubewharf/katalyst-core@v0.5.3/pkg/controller/resource-recommend/processor/percentile/process_gc.go (about)

     1  /*
     2  Copyright 2022 The Katalyst Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package percentile
    18  
    19  import (
    20  	"context"
    21  	"runtime/debug"
    22  	"time"
    23  
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/types"
    26  	"k8s.io/klog/v2"
    27  	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
    28  
    29  	"github.com/kubewharf/katalyst-api/pkg/apis/recommendation/v1alpha1"
    30  	"github.com/kubewharf/katalyst-core/pkg/controller/resource-recommend/processor/percentile/task"
    31  	"github.com/kubewharf/katalyst-core/pkg/util/resource-recommend/log"
    32  	processortypes "github.com/kubewharf/katalyst-core/pkg/util/resource-recommend/types/processor"
    33  )
    34  
    35  func (p *Processor) GarbageCollector(ctx context.Context) {
    36  	defer func() {
    37  		if r := recover(); r != nil {
    38  			errMsg := "garbage collect goroutine panic"
    39  			log.ErrorS(ctx, r.(error), errMsg, "stack", string(debug.Stack()))
    40  			panic(errMsg)
    41  		}
    42  	}()
    43  
    44  	ticker := time.Tick(DefaultGarbageCollectInterval)
    45  	for range ticker {
    46  		if err := p.garbageCollect(NewContext()); err != nil {
    47  			log.ErrorS(ctx, err, "garbageCollect failed")
    48  		}
    49  	}
    50  }
    51  
    52  func (p *Processor) garbageCollect(ctx context.Context) error {
    53  	defer func() {
    54  		if r := recover(); r != nil {
    55  			errMsg := "garbage collect run panic"
    56  			log.ErrorS(ctx, r.(error), errMsg, "stack", string(debug.Stack()))
    57  		}
    58  	}()
    59  
    60  	log.InfoS(ctx, "garbage collect start")
    61  
    62  	p.mutex.Lock()
    63  	defer p.mutex.Unlock()
    64  
    65  	// Tasks that have not been running for too long are considered invalid and will be cleared
    66  	p.AggregateTasks.Range(func(ki, vi any) bool {
    67  		taskID := ki.(processortypes.TaskID)
    68  		t, ok := vi.(*task.HistogramTask)
    69  		if !ok {
    70  			p.AggregateTasks.Delete(taskID)
    71  			return true
    72  		}
    73  		if t.IsTimeoutNotExecute() {
    74  			p.AggregateTasks.Delete(taskID)
    75  		}
    76  		return true
    77  	})
    78  
    79  	// List all ResourceRecommend CR up to now
    80  	resourceRecommendList := &v1alpha1.ResourceRecommendList{}
    81  	err := p.Client.List(ctx, resourceRecommendList, &k8sclient.ListOptions{Raw: &metav1.ListOptions{ResourceVersion: "0"}})
    82  	if err != nil {
    83  		log.ErrorS(ctx, err, "garbage collect list all ResourceRecommend failed")
    84  		return err
    85  	}
    86  
    87  	// p.ClearingNoAttributionTask(resourceRecommendList)
    88  	klog.InfoS("percentile processor garbage collect list ResourceRecommend",
    89  		"ResourceRecommend Count", len(resourceRecommendList.Items))
    90  	// Convert the ResourceRecommend list to map for quick check whether it exists
    91  	existResourceRecommends := make(map[types.NamespacedName]v1alpha1.CrossVersionObjectReference)
    92  	for _, existResourceRecommend := range resourceRecommendList.Items {
    93  		namespacedName := types.NamespacedName{
    94  			Name:      existResourceRecommend.Name,
    95  			Namespace: existResourceRecommend.Namespace,
    96  		}
    97  		existResourceRecommends[namespacedName] = existResourceRecommend.Spec.TargetRef
    98  	}
    99  
   100  	// Delete tasks belong to not exist ResourceRecommend or task not match the targetRef in the ResourceRecommend
   101  	for namespacedName, tasks := range p.ResourceRecommendTaskIDsMap {
   102  		if tasks == nil {
   103  			delete(p.ResourceRecommendTaskIDsMap, namespacedName)
   104  			continue
   105  		}
   106  		targetRef, isExist := existResourceRecommends[namespacedName]
   107  		for metrics, taskID := range *tasks {
   108  			if !isExist ||
   109  				targetRef.Kind != metrics.Kind ||
   110  				targetRef.Name != metrics.WorkloadName ||
   111  				targetRef.APIVersion != metrics.APIVersion {
   112  				p.AggregateTasks.Delete(taskID)
   113  				delete(*tasks, metrics)
   114  			}
   115  			//  timeout task in p.AggregateTasks will clean,
   116  			// If taskID does not exist in p.AggregateTasks,mean is the task is cleared, this needs to be deleted from tasks
   117  			if _, found := p.AggregateTasks.Load(taskID); !found {
   118  				delete(*tasks, metrics)
   119  			}
   120  		}
   121  		if !isExist {
   122  			delete(p.ResourceRecommendTaskIDsMap, namespacedName)
   123  		}
   124  	}
   125  
   126  	log.InfoS(ctx, "garbage collect end")
   127  	return nil
   128  }