volcano.sh/volcano@v1.9.0/pkg/scheduler/framework/job_updater.go (about)

     1  package framework
     2  
     3  import (
     4  	"context"
     5  	"math/rand"
     6  	"reflect"
     7  	"time"
     8  
     9  	"k8s.io/client-go/util/workqueue"
    10  	"k8s.io/klog/v2"
    11  
    12  	"volcano.sh/apis/pkg/apis/scheduling"
    13  	"volcano.sh/volcano/pkg/scheduler/api"
    14  )
    15  
    16  const (
    17  	jobUpdaterWorker = 16
    18  )
    19  
    20  // TimeJitterAfter means: new after old + duration + jitter
    21  func TimeJitterAfter(new, old time.Time, duration, maxJitter time.Duration) bool {
    22  	var jitter int64
    23  	if maxJitter > 0 {
    24  		jitter = rand.Int63n(int64(maxJitter))
    25  	}
    26  	return new.After(old.Add(duration + time.Duration(jitter)))
    27  }
    28  
    29  type jobUpdater struct {
    30  	ssn      *Session
    31  	jobQueue []*api.JobInfo
    32  }
    33  
    34  func newJobUpdater(ssn *Session) *jobUpdater {
    35  	queue := make([]*api.JobInfo, 0, len(ssn.Jobs))
    36  	for _, job := range ssn.Jobs {
    37  		queue = append(queue, job)
    38  	}
    39  
    40  	ju := &jobUpdater{
    41  		ssn:      ssn,
    42  		jobQueue: queue,
    43  	}
    44  	return ju
    45  }
    46  
    47  func (ju *jobUpdater) UpdateAll() {
    48  	workqueue.ParallelizeUntil(context.TODO(), jobUpdaterWorker, len(ju.jobQueue), ju.updateJob)
    49  }
    50  
    51  func isPodGroupConditionsUpdated(newCondition, oldCondition []scheduling.PodGroupCondition) bool {
    52  	if len(newCondition) != len(oldCondition) {
    53  		return true
    54  	}
    55  
    56  	for index, newCond := range newCondition {
    57  		oldCond := oldCondition[index]
    58  
    59  		newTime := newCond.LastTransitionTime
    60  		oldTime := oldCond.LastTransitionTime
    61  
    62  		// if newCond is not new enough, we treat it the same as the old one
    63  		newCond.LastTransitionTime = oldTime
    64  
    65  		// comparing should ignore the TransitionID
    66  		newTransitionID := newCond.TransitionID
    67  		newCond.TransitionID = oldCond.TransitionID
    68  
    69  		shouldUpdate := !reflect.DeepEqual(&newCond, &oldCond)
    70  
    71  		newCond.LastTransitionTime = newTime
    72  		newCond.TransitionID = newTransitionID
    73  		if shouldUpdate {
    74  			return true
    75  		}
    76  	}
    77  
    78  	return false
    79  }
    80  
    81  func isPodGroupStatusUpdated(newStatus, oldStatus scheduling.PodGroupStatus) bool {
    82  	newCondition := newStatus.Conditions
    83  	newStatus.Conditions = nil
    84  	oldCondition := oldStatus.Conditions
    85  	oldStatus.Conditions = nil
    86  
    87  	return !reflect.DeepEqual(newStatus, oldStatus) || isPodGroupConditionsUpdated(newCondition, oldCondition)
    88  }
    89  
    90  // updateJob update specified job
    91  func (ju *jobUpdater) updateJob(index int) {
    92  	job := ju.jobQueue[index]
    93  	ssn := ju.ssn
    94  
    95  	job.PodGroup.Status = jobStatus(ssn, job)
    96  	oldStatus, found := ssn.podGroupStatus[job.UID]
    97  	updatePG := !found || isPodGroupStatusUpdated(job.PodGroup.Status, oldStatus)
    98  	if _, err := ssn.cache.UpdateJobStatus(job, updatePG); err != nil {
    99  		klog.Errorf("Failed to update job <%s/%s>: %v",
   100  			job.Namespace, job.Name, err)
   101  	}
   102  }