Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/http-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ with no `address`:
]
```

Runner records also carry mode, capacity, prices, and optional metadata/GPU fields.
Runner records also carry `runner_id` (the registered runner identity), mode, capacity,
prices, and optional metadata/GPU fields. Consumers can bind admission to this identity
without deriving it from the proxy URL or conflating it with the application name.
Discovery preserves complete runner records. `nodes` lists successfully queried,
non-evicted sources, and `queried_at` records each source's last successful query
time. Empty node and runner lists are omitted. With neither to advertise, discovery
Expand Down
9 changes: 8 additions & 1 deletion orchestrator/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,13 +353,20 @@ func TestTrickleChannelsScopedToSession(t *testing.T) {

func TestRunnerGPUIsPreservedForPythonDiscovery(t *testing.T) {
var request heartbeatRequest
require.NoError(t, json.Unmarshal([]byte(`{"runner_id":"gpu-runner","runner_url":"https://runner.example","app":"retained","mode":"single-shot","status":"ready","capacity":1,"gpu":{"id":"0","name":"H100","vram_mb":80000}}`), &request))
require.NoError(t, json.Unmarshal([]byte(`{"runner_id":"gpu-runner","proxy":true,"runner_url":"https://runner.example","app":"retained","mode":"single-shot","status":"ready","capacity":1,"gpu":{"id":"0","name":"H100","vram_mb":80000}}`), &request))
registry := NewRegistry("bootstrap", "https://orchestrator.example", time.Second, 30*time.Second)
registry.proxyTemplate = "https://{proxy}.example"
_, status, err := registry.Heartbeat(request, "bootstrap")
require.NoError(t, err)
require.Equal(t, http.StatusOK, status)
entries := registry.Discovery()
require.Len(t, entries, 1)
require.Len(t, entries[0].Runners, 1)
require.Equal(t, "H100", entries[0].Runners[0].GPU.Name)
encoded, err := json.Marshal(entries[0].Runners[0])
require.NoError(t, err)
var record map[string]any
require.NoError(t, json.Unmarshal(encoded, &record))
require.Equal(t, "gpu-runner", record["runner_id"])
Comment thread
cursor[bot] marked this conversation as resolved.
Resolved
require.Equal(t, "https://gpu-runner.example", record["url"])
}
3 changes: 2 additions & 1 deletion orchestrator/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@
return true
}

func (r *Registry) Heartbeat(req heartbeatRequest, auth string) (heartbeatResponse, int, error) {

Check failure on line 297 in orchestrator/registry.go

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 16 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=NE-Build-Track_node&issues=AaF-Qmbi8qMpAakNiTU9&open=AaF-Qmbi8qMpAakNiTU9&pullRequest=1
if err := validateHeartbeat(&req); err != nil {
return heartbeatResponse{}, http.StatusBadRequest, err
}
Expand Down Expand Up @@ -384,6 +384,7 @@
}

type discoveryRunner struct {
RunnerID string `json:"runner_id"`
Comment thread
cursor[bot] marked this conversation as resolved.
Resolved
ObservedAt string `json:"observed_at"`
URL string `json:"url"`
App string `json:"app"`
Expand Down Expand Up @@ -414,7 +415,7 @@
continue
}
available := max(0, item.Capacity-len(item.Sessions))
result = append(result, discoveryRunner{ObservedAt: observed, URL: r.discoveryURL(id, item), App: item.App, Version: item.Version, Metadata: item.Metadata, GPU: item.GPU, Mode: item.Mode, Capacity: item.Capacity, CapacityUsed: len(item.Sessions), CapacityAvailable: available, PriceInfo: item.PriceInfo})
result = append(result, discoveryRunner{RunnerID: id, ObservedAt: observed, URL: r.discoveryURL(id, item), App: item.App, Version: item.Version, Metadata: item.Metadata, GPU: item.GPU, Mode: item.Mode, Capacity: item.Capacity, CapacityUsed: len(item.Sessions), CapacityAvailable: available, PriceInfo: item.PriceInfo})
}
return []discoveryEntry{{Address: r.service, Runners: result}}
}
Expand Down
8 changes: 7 additions & 1 deletion signer/discovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func discoveryResponse(s *Service, query string) *httptest.ResponseRecorder {
}

func TestSignerDiscovery(t *testing.T) {
const advertised = `[{"address":"http://localhost:9000","runners":[{"url":"http://localhost:9000/app","observed_at":"2026-01-01T00:00:00Z","app":"retained","version":"v1","metadata":"model-x","mode":"single-shot","gpu":{"id":"0","name":" H100 ","vram_mb":80000},"capacity":3,"capacity_used":1,"capacity_available":2,"price_info":{"price":10,"price_usd":0.1,"currency":"wei","unit":"fixed"}},{"url":"http://localhost:9000/cpu","observed_at":"2026-01-01T00:00:00Z","app":"cpu","mode":"single-shot","capacity":1,"price_info":{"price":1,"currency":"wei","unit":"fixed"}}]}]`
const advertised = `[{"address":"http://localhost:9000","runners":[{"runner_id":"gpu-runner","url":"https://gpu-runner.example","observed_at":"2026-01-01T00:00:00Z","app":"retained","version":"v1","metadata":"model-x","mode":"single-shot","gpu":{"id":"0","name":" H100 ","vram_mb":80000},"capacity":3,"capacity_used":1,"capacity_available":2,"price_info":{"price":10,"price_usd":0.1,"currency":"wei","unit":"fixed"}},{"url":"http://localhost:9000/cpu","observed_at":"2026-01-01T00:00:00Z","app":"cpu","mode":"single-shot","capacity":1,"price_info":{"price":1,"currency":"wei","unit":"fixed"}}]}]`
bodies := map[string]string{
"empty": "[]", "good": advertised, "failed": "", "malformed": "not JSON",
"metadata": `[{"nodes":[]}]`,
Expand Down Expand Up @@ -124,6 +124,12 @@ func TestSignerDiscovery(t *testing.T) {
require.Equal(t, expected[0].Address, result[0].Address)
want := slices.DeleteFunc(slices.Clone(expected[0].Runners), func(r discoveredRunner) bool { return !slices.Contains(test.apps, r.App) })
require.Equal(t, want, result[0].Runners, "preserve advertised fields and URLs")
for _, runner := range result[0].Runners {
if runner.App == "retained" {
require.Equal(t, "gpu-runner", runner.RunnerID)
require.Equal(t, "https://gpu-runner.example", runner.URL)
}
}
})
}
}
Expand Down
1 change: 1 addition & 0 deletions signer/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ type discoveredGPU struct {
}

type discoveredRunner struct {
RunnerID string `json:"runner_id,omitempty"`
ObservedAt string `json:"observed_at"`
URL string `json:"url"`
App string `json:"app"`
Expand Down
Loading