diff --git a/pkg/scheduler/backend/queue/scheduling_queue.go b/pkg/scheduler/backend/queue/scheduling_queue.go index a2d326e6303..d1b83fe6dd8 100644 --- a/pkg/scheduler/backend/queue/scheduling_queue.go +++ b/pkg/scheduler/backend/queue/scheduling_queue.go @@ -413,6 +413,18 @@ func (p *PriorityQueue) isPodWorthRequeuing(logger klog.Logger, pInfo *framework } if event.IsWildCard() { + // If the wildcard event has a Pod in newObj, + // that indicates that the event wants to be effective for the Pod only. + // Specifically, EventForceActivate could have a target Pod in newObj. + if newObj != nil { + if pod, ok := newObj.(*v1.Pod); ok && pod.UID == pInfo.Pod.UID { + logger.V(6).Info("Worth requeuing because the event is wildcard", "pod", klog.KObj(pInfo.Pod)) + return queueAfterBackoff + } + // This wildcard event is not for this Pod. + return queueSkip + } + // If the wildcard event is special one as someone wants to force all Pods to move to activeQ/backoffQ. // We return queueAfterBackoff in this case, while resetting all blocked plugins. logger.V(6).Info("Worth requeuing because the event is wildcard", "pod", klog.KObj(pInfo.Pod)) @@ -609,6 +621,8 @@ func (p *PriorityQueue) Activate(logger klog.Logger, pods map[string]*v1.Pod) { } // If this pod is in-flight, register the activation event so that the pod will be requeued when it comes back. + // Specifically in the in-tree plugins, this is for the scenario with the preemption plugin + // where the async preemption API calls are all done or fail at some point before the Pod comes back to the queue. p.activeQ.addEventsIfPodInFlight(nil, pod, []framework.ClusterEvent{framework.EventForceActivate}) } diff --git a/pkg/scheduler/backend/queue/scheduling_queue_test.go b/pkg/scheduler/backend/queue/scheduling_queue_test.go index 5c74bd130ef..ce4c1918156 100644 --- a/pkg/scheduler/backend/queue/scheduling_queue_test.go +++ b/pkg/scheduler/backend/queue/scheduling_queue_test.go @@ -3838,6 +3838,7 @@ func mustNewPodInfo(pod *v1.Pod) *framework.PodInfo { // Test_isPodWorthRequeuing tests isPodWorthRequeuing function. func Test_isPodWorthRequeuing(t *testing.T) { + metrics.Register() count := 0 queueHintReturnQueue := func(logger klog.Logger, pod *v1.Pod, oldObj, newObj interface{}) (framework.QueueingHint, error) { count++ @@ -3916,11 +3917,37 @@ func Test_isPodWorthRequeuing(t *testing.T) { }, event: framework.EventUnschedulableTimeout, oldObj: nil, - newObj: st.MakeNode().Obj(), + newObj: nil, expected: queueAfterBackoff, expectedExecutionCount: 0, queueingHintMap: QueueingHintMapPerProfile{}, }, + { + name: "return Queue when the event is wildcard and the wildcard targets the pod to be requeued right now", + podInfo: &framework.QueuedPodInfo{ + UnschedulablePlugins: sets.New("fooPlugin1"), + PodInfo: mustNewPodInfo(st.MakePod().Name("pod1").Namespace("ns1").UID("1").Obj()), + }, + event: framework.EventForceActivate, + oldObj: nil, + newObj: st.MakePod().Name("pod1").Namespace("ns1").UID("1").Obj(), + expected: queueAfterBackoff, + expectedExecutionCount: 0, + queueingHintMap: QueueingHintMapPerProfile{}, + }, + { + name: "return Skip when the event is wildcard, but the wildcard targets a different pod", + podInfo: &framework.QueuedPodInfo{ + UnschedulablePlugins: sets.New("fooPlugin1"), + PodInfo: mustNewPodInfo(st.MakePod().Name("pod1").Namespace("ns1").UID("1").Obj()), + }, + event: framework.EventForceActivate, + oldObj: nil, + newObj: st.MakePod().Name("pod-different").Namespace("ns2").UID("2").Obj(), + expected: queueSkip, + expectedExecutionCount: 0, + queueingHintMap: QueueingHintMapPerProfile{}, + }, { name: "interprets Queue from the Pending plugin as queueImmediately", podInfo: &framework.QueuedPodInfo{