@@ -19,6 +19,7 @@ package runner
1919import (
2020"context"
2121"crypto/tls"
22+ "encoding/json"
2223"errors"
2324"flag"
2425"fmt"
@@ -42,6 +43,7 @@ import (
4243"sigs.k8s.io/controller-runtime/pkg/manager"
4344"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
4445metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
46+
4547"sigs.k8s.io/gateway-api-inference-extension/internal/runnable"
4648"sigs.k8s.io/gateway-api-inference-extension/pkg/common"
4749backendmetrics "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/backend/metrics"
@@ -243,12 +245,6 @@ func (r *Runner) Run(ctx context.Context) error {
243245runtime .SetBlockProfileRate (1 )
244246}
245247
246- err = r .parsePluginsConfiguration (ctx )
247- if err != nil {
248- setupLog .Error (err , "Failed to parse the configuration" )
249- return err
250- }
251-
252248// ===================================================================
253249// == Latency Predictor Integration
254250// ===================================================================
@@ -267,8 +263,14 @@ func (r *Runner) Run(ctx context.Context) error {
267263setupLog .Info ("Latency predictor is disabled." )
268264predictor = nil // This will be a true nil interface
269265}
270-
271266// ===================================================================
267+
268+ err = r .parsePluginsConfiguration (ctx , predictor , datastore )
269+ if err != nil {
270+ setupLog .Error (err , "Failed to parse the configuration" )
271+ return err
272+ }
273+
272274// --- Initialize Core EPP Components ---
273275if r .schedulerConfig == nil {
274276err := errors .New ("scheduler config must be set either by config api or through code" )
@@ -282,10 +284,6 @@ func (r *Runner) Run(ctx context.Context) error {
282284
283285saturationDetector := saturationdetector .NewDetector (sdConfig , setupLog )
284286
285- if * enableLatencyPredictor {
286- r .requestControlConfig .AddPlugins (slorequest .New (datastore , predictor ))
287- }
288-
289287director := requestcontrol .NewDirectorWithConfig (datastore , scheduler , saturationDetector , r .requestControlConfig )
290288
291289// --- Setup ExtProc Server Runner ---
@@ -315,11 +313,13 @@ func (r *Runner) Run(ctx context.Context) error {
315313return err
316314}
317315
316+ // Register ext-proc server.
318317if err := registerExtProcServer (mgr , serverRunner , ctrl .Log .WithName ("ext-proc" )); err != nil {
319318return err
320319}
321320
322321// --- Start Manager ---
322+ // This blocks until a signal is received.
323323setupLog .Info ("Controller manager starting" )
324324if err := mgr .Start (ctx ); err != nil {
325325setupLog .Error (err , "Error starting controller manager" )
@@ -342,7 +342,18 @@ func (r *Runner) registerInTreePlugins() {
342342plugins .Register (testfilter .HeaderBasedTestingFilterType , testfilter .HeaderBasedTestingFilterFactory )
343343}
344344
345- func (r * Runner ) parsePluginsConfiguration (ctx context.Context ) error {
345+ func (r * Runner ) registerLatencyPredictorPlugins (predictor latencypredictor.PredictorInterface , datastore datastore.Datastore ) {
346+ // Register the SLO request tracker and scorer plugin, these plugins need access to the predictor and datastore.
347+ // We have to specify a custom factory function to create the plugins with the correct dependencies.
348+ plugins .Register (slorequest .SLORequestTrackerPluginType , func (name string , _ json.RawMessage , _ plugins.Handle ) (plugins.Plugin , error ) {
349+ return slorequest .New (predictor , datastore ).WithName (name ), nil
350+ })
351+ plugins .Register (scorer .SLOScorerPluginType , func (name string , _ json.RawMessage , _ plugins.Handle ) (plugins.Plugin , error ) {
352+ return scorer .NewSLOScorer (predictor , datastore ).WithName (name ), nil
353+ })
354+ }
355+
356+ func (r * Runner ) parsePluginsConfiguration (ctx context.Context , predictor latencypredictor.PredictorInterface , datastore datastore.Datastore ) error {
346357if * configText == "" && * configFile == "" {
347358return nil // configuring through code, not through file
348359}
@@ -361,6 +372,12 @@ func (r *Runner) parsePluginsConfiguration(ctx context.Context) error {
361372}
362373
363374r .registerInTreePlugins ()
375+ // If we have a latency predictor enabled and predictor and datastore are not nil,
376+ // register the latency predictor plugins (currently just the SLO scorer).
377+ if * enableLatencyPredictor && predictor != nil && datastore != nil {
378+ setupLog .Info ("Registering latency predictor plugins" )
379+ r .registerLatencyPredictorPlugins (predictor , datastore )
380+ }
364381handle := plugins .NewEppHandle (ctx )
365382config , err := loader .LoadConfig (configBytes , handle , logger )
366383if err != nil {
@@ -477,13 +494,15 @@ func (r *Runner) parseConfiguration(ctx context.Context) error {
477494}
478495
479496func initLogging (opts * zap.Options ) {
497+ // Unless -zap-log-level is explicitly set, use -v
480498useV := true
481499flag .Visit (func (f * flag.Flag ) {
482500if f .Name == "zap-log-level" {
483501useV = false
484502}
485503})
486504if useV {
505+ // See https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/log/zap#Options.Level
487506lvl := - 1 * (* logVerbosity )
488507opts .Level = uberzap .NewAtomicLevelAt (zapcore .Level (int8 (lvl )))
489508}
@@ -543,11 +562,10 @@ func verifyMetricMapping(mapping backendmetrics.MetricMapping, logger logr.Logge
543562if mapping .LoraRequestInfo == nil {
544563logger .Info ("Not scraping metric: LoraRequestInfo" )
545564}
546- if mapping .TotalRunningRequests == nil {
547- logger .Info ("Not scraping metric: TotalRunningRequests" )
548- }
549565}
550566
567+ // setupPprofHandlers only implements the pre-defined profiles:
568+ // https://cs.opensource.google/go/go/+/refs/tags/go1.24.4:src/runtime/pprof/pprof.go;l=108
551569func setupPprofHandlers (mgr ctrl.Manager ) error {
552570var err error
553571profiles := []string {
0 commit comments