diff --git a/pkg/epp/scheduling/plugins/pickers/max-score.go b/pkg/epp/scheduling/plugins/pickers/max-score.go new file mode 100644 index 000000000..329d8006f --- /dev/null +++ b/pkg/epp/scheduling/plugins/pickers/max-score.go @@ -0,0 +1,54 @@ +package pickers + +import ( + "fmt" + + "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/types" + logutil "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/util/logging" +) + +// MaxScorePicker picks the pod with the maximum score from the list of +// candidates. +type MaxScorePicker struct{} + +var _ types.Picker = &MaxScorePicker{} + +// Name returns the name of the picker. +func (msp *MaxScorePicker) Name() string { + return "max-score" +} + +// Pick selects the pod with the maximum score from the list of candidates. +func (msp *MaxScorePicker) Pick(ctx *types.Context, pods []types.Pod) (*types.Result, error) { + debugLogger := ctx.Logger.V(logutil.DEBUG).WithName("max-score-picker") + debugLogger.Info(fmt.Sprintf("Selecting the pod with the max score from %d candidates: %+v", + len(pods), pods)) + + winners := make([]types.Pod, 0) + + maxScore := 0.0 + for _, pod := range pods { + score := pod.Score() + if score > maxScore { + maxScore = score + winners = []types.Pod{pod} + } else if score == maxScore { + winners = append(winners, pod) + } + } + + if len(winners) == 0 { + return nil, nil + } + + if len(winners) > 1 { + debugLogger.Info(fmt.Sprintf("Multiple pods have the same max score (%f): %+v", + maxScore, winners)) + + randomPicker := RandomPicker{} + return randomPicker.Pick(ctx, winners) + } + + debugLogger.Info(fmt.Sprintf("Selected pod with max score (%f): %+v", maxScore, winners[0])) + return &types.Result{TargetPod: winners[0]}, nil +} diff --git a/pkg/epp/scheduling/plugins/picker.go b/pkg/epp/scheduling/plugins/pickers/random.go similarity index 83% rename from pkg/epp/scheduling/plugins/picker.go rename to pkg/epp/scheduling/plugins/pickers/random.go index 569e4e86a..65eb42180 100644 --- a/pkg/epp/scheduling/plugins/picker.go +++ b/pkg/epp/scheduling/plugins/pickers/random.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package plugins +package pickers import ( "fmt" @@ -24,12 +24,17 @@ import ( logutil "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/util/logging" ) +// RandomPicker picks a pod randomly from the list of candidates. type RandomPicker struct{} +var _ types.Picker = &RandomPicker{} + +// Name returns the name of the picker. func (rp *RandomPicker) Name() string { return "random" } +// Pick selects a random pod from the list of candidates. func (rp *RandomPicker) Pick(ctx *types.Context, pods []types.Pod) (*types.Result, error) { ctx.Logger.V(logutil.DEBUG).Info(fmt.Sprintf("Selecting a random pod from %d candidates: %+v", len(pods), pods)) i := rand.Intn(len(pods)) diff --git a/pkg/epp/scheduling/scheduler.go b/pkg/epp/scheduling/scheduler.go index 2a266fade..373d6decb 100644 --- a/pkg/epp/scheduling/scheduler.go +++ b/pkg/epp/scheduling/scheduler.go @@ -26,6 +26,7 @@ import ( backendmetrics "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/backend/metrics" "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/metrics" "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/plugins" + "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/plugins/pickers" "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/scheduling/types" logutil "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/util/logging" ) @@ -74,7 +75,7 @@ func NewScheduler(datastore Datastore) *Scheduler { postSchedulePlugins: []types.PostSchedule{}, scorers: []types.Scorer{}, filters: []types.Filter{defaultPlugin}, - picker: defaultPlugin, + picker: &pickers.MaxScorePicker{}, } } @@ -198,7 +199,7 @@ func runScorersForPod(ctx *types.Context, scorers []types.Scorer, pod types.Pod) } type defaultPlugin struct { - plugins.RandomPicker + pickers.RandomPicker } func (p *defaultPlugin) Name() string { diff --git a/pkg/epp/scheduling/types/interfaces.go b/pkg/epp/scheduling/types/interfaces.go index 6e954cef0..d41951978 100644 --- a/pkg/epp/scheduling/types/interfaces.go +++ b/pkg/epp/scheduling/types/interfaces.go @@ -63,6 +63,7 @@ type Filter interface { } // Scorer defines the interface for scoring pods based on context. +// Scorers must return a score between 0 and 1, where 1 is the best score. type Scorer interface { Plugin Score(ctx *Context, pod Pod) (float64, error)