Skip to content

Commit 97fcf9e

Browse files
committed
feat(datalayer): move interval to plugin parameters
Signed-off-by: noalimoy <nlimoy@redhat.com>
1 parent a0d8f1b commit 97fcf9e

17 files changed

Lines changed: 91 additions & 41 deletions

File tree

apix/config/v1alpha1/endpointpickerconfig_types.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -278,13 +278,6 @@ type DataLayerSource struct {
278278
// this Source. The entries are references to the names of entries of the Plugins
279279
// defined in the configuration's Plugins section
280280
Extractors []DataLayerExtractor `json:"extractors"`
281-
282-
// +optional
283-
// Interval is the scrape period for this polling source. It must be a
284-
// positive multiple of --refresh-metrics-interval (default 50ms). When
285-
// omitted, the source runs on every base tick. Ignored for
286-
// notification/endpoint sources.
287-
Interval *metav1.Duration `json:"interval,omitempty"`
288281
}
289282

290283
func (dls DataLayerSource) String() string {
@@ -293,9 +286,6 @@ func (dls DataLayerSource) String() string {
293286
if len(dls.Extractors) > 0 {
294287
parts = append(parts, fmt.Sprintf("Extractors: %v", dls.Extractors))
295288
}
296-
if dls.Interval != nil {
297-
parts = append(parts, "Interval: "+dls.Interval.Duration.String())
298-
}
299289
return "{" + strings.Join(parts, ", ") + "}"
300290
}
301291

apix/config/v1alpha1/zz_generated.deepcopy.go

Lines changed: 0 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deploy/config/sim-epp-gpu-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ plugins:
77
name: dcgm-source
88
parameters:
99
port: 9400
10+
interval: "1s"
1011
- type: dcgm-extractor
1112
name: dcgm-extractor
1213
- type: endpoint-attribute-filter
@@ -37,7 +38,6 @@ plugins:
3738
dataLayer:
3839
sources:
3940
- pluginRef: dcgm-source
40-
interval: 1s
4141
extractors:
4242
- pluginRef: dcgm-extractor
4343
schedulingProfiles:

docs/architecture.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,10 @@ The data layer follows a Source -> Extract -> Attribute lifecycle:
225225
- Scoring can rely on numerical metrics or metadata (model ID, adapter tags)
226226

227227
Polling sources share one Collector goroutine per endpoint. The base tick is
228-
`--refresh-metrics-interval` (default 50ms). A polling entry under `dataLayer.sources`
229-
may set `interval` to a positive multiple of that base tick; when omitted, the source
230-
runs on every base tick. Example: `interval: 1s` with the default base tick scrapes
231-
that source once per second.
228+
`--refresh-metrics-interval` (default 50ms). Each polling source plugin accepts an
229+
`interval` parameter (e.g. `"1s"`) that must be a positive multiple of the base tick;
230+
when omitted, the source runs on every base tick. The runtime converts each source's
231+
interval to base-tick multiples and schedules dispatches accordingly.
232232

233233
See the upstream [Data Layer](https://github.com/llm-d/llm-d/blob/main/docs/architecture/core/router/epp/datalayer.md) doc for the canonical model.
234234

pkg/epp/config/loader/configloader.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -438,9 +438,6 @@ func buildDataLayerConfig(rawDataConfig *configapi.DataLayerConfig, handle fwkpl
438438
Plugin: sourcePlugin,
439439
Extractors: []fwkplugin.Plugin{},
440440
}
441-
if source.Interval != nil {
442-
sourceConfig.Interval = source.Interval.Duration
443-
}
444441
for _, extractor := range source.Extractors {
445442
extractorPlugin := handle.Plugin(extractor.PluginRef)
446443
if extractorPlugin == nil {

pkg/epp/datalayer/collector_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ func (e *errSource) Dispatch(_ context.Context, _ fwkdl.Endpoint) error {
8080
return e.err
8181
}
8282
func (e *errSource) AppendExtractor(_ fwkplugin.Plugin) error { return nil }
83+
func (e *errSource) Interval() time.Duration { return 0 }
8384

8485
type dataSource struct {
8586
kind string
@@ -115,6 +116,7 @@ func (d *dataSource) AppendExtractor(p fwkplugin.Plugin) error {
115116
d.mu.Unlock()
116117
return nil
117118
}
119+
func (d *dataSource) Interval() time.Duration { return 0 }
118120

119121
type stubExtractor struct {
120122
kind string

pkg/epp/datalayer/config.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package datalayer
1818

1919
import (
2020
"fmt"
21-
"time"
2221

2322
"github.com/llm-d/llm-d-router/pkg/epp/framework/interface/plugin"
2423
)
@@ -50,9 +49,6 @@ func (c *Config) String() string {
5049
type DataSourceConfig struct {
5150
Plugin plugin.Plugin // the source plugin instance (DataSource or PollingDispatcher)
5251
Extractors []plugin.Plugin // extractors defined for the data source
53-
// Interval is the scrape period for polling sources. Zero means every
54-
// Runtime base tick. Ignored for notification/endpoint sources.
55-
Interval time.Duration
5652
}
5753

5854
func (dsc DataSourceConfig) String() string {

pkg/epp/datalayer/runtime.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ func (r *Runtime) Configure(cfg *Config, logger logr.Logger) error {
121121
}
122122

123123
periodTicks := 1
124-
if _, ok := src.(fwkdl.PollingDispatcher); ok {
124+
if disp, ok := src.(fwkdl.PollingDispatcher); ok {
125125
var err error
126-
periodTicks, err = PeriodTicks(srcCfg.Interval, r.pollingInterval)
126+
periodTicks, err = PeriodTicks(disp.Interval(), r.pollingInterval)
127127
if err != nil {
128128
return fmt.Errorf("source %s: %w", srcName, err)
129129
}

pkg/epp/datalayer/runtime_validate_test.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ func (m *multiVariantSource) TypedName() fwkplugin.TypedName
123123
func (m *multiVariantSource) GVK() schema.GroupVersionKind { return m.gvk }
124124
func (m *multiVariantSource) Dispatch(_ context.Context, _ fwkdl.Endpoint) error { return nil }
125125
func (m *multiVariantSource) AppendExtractor(_ fwkplugin.Plugin) error { return nil }
126+
func (m *multiVariantSource) Interval() time.Duration { return 0 }
126127
func (m *multiVariantSource) Notify(_ context.Context, event fwkdl.NotificationEvent) (*fwkdl.NotificationEvent, error) {
127128
// Body never runs in this test. Configure rejects the source for
128129
// implementing multiple variants before any Notify call. Echo the
@@ -148,14 +149,21 @@ func TestRuntimeConfigure_SourceImplementingMultipleVariants_Rejected(t *testing
148149
assert.Contains(t, err.Error(), "multiple variant")
149150
}
150151

152+
// intervalMockSource wraps MetricsDataSource with a configurable Interval.
153+
type intervalMockSource struct {
154+
mocks.MetricsDataSource
155+
interval time.Duration
156+
}
157+
158+
func (s *intervalMockSource) Interval() time.Duration { return s.interval }
159+
151160
func TestRuntimeConfigure_InvalidSourceInterval(t *testing.T) {
152161
logger := newTestLogger(t)
153162
r := NewRuntime(50 * time.Millisecond)
154163

155164
cfg := &Config{
156165
Sources: []DataSourceConfig{{
157-
Plugin: &mocks.MetricsDataSource{},
158-
Interval: 75 * time.Millisecond,
166+
Plugin: &intervalMockSource{interval: 75 * time.Millisecond},
159167
}},
160168
}
161169

@@ -170,8 +178,7 @@ func TestRuntimeConfigure_SourceIntervalStoredAsPeriodTicks(t *testing.T) {
170178

171179
cfg := &Config{
172180
Sources: []DataSourceConfig{{
173-
Plugin: &mocks.MetricsDataSource{},
174-
Interval: time.Second,
181+
Plugin: &intervalMockSource{interval: time.Second},
175182
}},
176183
}
177184

pkg/epp/framework/interface/datalayer/plugin.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package datalayer
1818

1919
import (
2020
"context"
21+
"time"
2122

2223
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2324
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -74,10 +75,12 @@ type NotificationExtractor interface {
7475
// DataLayerExtractErrorsTotal and do NOT surface as the return error.
7576
// - AppendExtractor is a pure append; duplicate-Type detection is the caller's
7677
// responsibility (see runtime.Configure).
78+
// - Interval returns the desired scrape period. Zero means every base tick.
7779
type PollingDispatcher interface {
7880
plugin.Plugin
7981
Dispatch(ctx context.Context, ep Endpoint) error
8082
AppendExtractor(ext plugin.Plugin) error
83+
Interval() time.Duration
8184
}
8285

8386
// EventType identifies the type of mutation that triggered a notification.

0 commit comments

Comments
 (0)