From c4634d861e9d90891a14b3d2e1e29ee5c37fda08 Mon Sep 17 00:00:00 2001 From: tinswzy Date: Tue, 8 Jul 2025 22:56:47 +0800 Subject: [PATCH] fix: v2.6 WebUI metrics response schema change bug (#42957) #42919 fix metrics response schema incompatibility with WebUI v2.6 Signed-off-by: tinswzy --- internal/coordinator/mix_coord.go | 10 +++++ internal/proxy/http_req_impl.go | 4 +- pkg/util/metricsinfo/metric_request.go | 15 +++++++ pkg/util/metricsinfo/metric_request_test.go | 50 +++++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) diff --git a/internal/coordinator/mix_coord.go b/internal/coordinator/mix_coord.go index ceaaa7341e..2c151ba1aa 100644 --- a/internal/coordinator/mix_coord.go +++ b/internal/coordinator/mix_coord.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/tidwall/gjson" "github.com/tikv/client-go/v2/txnkv" clientv3 "go.etcd.io/etcd/client/v3" "go.uber.org/atomic" @@ -582,6 +583,15 @@ func (s *mixCoordImpl) GetMetrics(ctx context.Context, in *milvuspb.GetMetricsRe NodesInfo: make([]metricsinfo.SystemTopologyNode, 0), } + // If a processing role is specified, the corresponding role will be used for processing + ret := gjson.Parse(in.GetRequest()) + processRole, _ := metricsinfo.ParseMetricProcessInRole(ret) + if len(processRole) > 0 && processRole == typeutil.QueryCoordRole { + return s.GetQcMetrics(ctx, in) + } else if len(processRole) > 0 && processRole == typeutil.DataCoordRole { + return s.GetDcMetrics(ctx, in) + } + identifierMap := make(map[string]int) rootCoordResp, rootCoordErr := s.rootcoordServer.GetMetrics(ctx, in) diff --git a/internal/proxy/http_req_impl.go b/internal/proxy/http_req_impl.go index 30445a51ee..099f11b0b8 100644 --- a/internal/proxy/http_req_impl.go +++ b/internal/proxy/http_req_impl.go @@ -169,7 +169,7 @@ func buildReqParams(c *gin.Context, metricsType string, customParams ...*commonp func getQueryComponentMetrics(node *Proxy, metricsType string, customParams ...*commonpb.KeyValuePair) gin.HandlerFunc { return func(c *gin.Context) { - params := buildReqParams(c, metricsType) + params := buildReqParams(c, metricsType, metricsinfo.RequestProcessInQCRole) req, err := metricsinfo.ConstructGetMetricsRequest(params) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ @@ -191,7 +191,7 @@ func getQueryComponentMetrics(node *Proxy, metricsType string, customParams ...* func getDataComponentMetrics(node *Proxy, metricsType string, customParams ...*commonpb.KeyValuePair) gin.HandlerFunc { return func(c *gin.Context) { - params := buildReqParams(c, metricsType) + params := buildReqParams(c, metricsType, metricsinfo.RequestProcessInDCRole) req, err := metricsinfo.ConstructGetMetricsRequest(params) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ diff --git a/pkg/util/metricsinfo/metric_request.go b/pkg/util/metricsinfo/metric_request.go index d880771f0d..bc00b32713 100644 --- a/pkg/util/metricsinfo/metric_request.go +++ b/pkg/util/metricsinfo/metric_request.go @@ -26,6 +26,7 @@ import ( "github.com/milvus-io/milvus/pkg/v2/common" "github.com/milvus-io/milvus/pkg/v2/log" "github.com/milvus-io/milvus/pkg/v2/util/commonpbutil" + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) const ( @@ -93,6 +94,8 @@ const ( MetricsRequestParamsInQC = "qc" MetricsRequestParamsInDN = "dn" MetricsRequestParamsInQN = "qn" + + MetricRequestProcessInRoleKey = "ProcessRole" ) var ( @@ -100,6 +103,9 @@ var ( RequestParamsInQC = &commonpb.KeyValuePair{Key: MetricRequestParamINKey, Value: MetricsRequestParamsInQC} RequestParamsInDN = &commonpb.KeyValuePair{Key: MetricRequestParamINKey, Value: MetricsRequestParamsInDN} RequestParamsInQN = &commonpb.KeyValuePair{Key: MetricRequestParamINKey, Value: MetricsRequestParamsInQN} + + RequestProcessInDCRole = &commonpb.KeyValuePair{Key: MetricRequestProcessInRoleKey, Value: typeutil.DataCoordRole} + RequestProcessInQCRole = &commonpb.KeyValuePair{Key: MetricRequestProcessInRoleKey, Value: typeutil.QueryCoordRole} ) type MetricsRequestAction func(ctx context.Context, req *milvuspb.GetMetricsRequest, jsonReq gjson.Result) (string, error) @@ -176,6 +182,15 @@ func ParseMetricRequestType(jsonRet gjson.Result) (string, error) { return "", fmt.Errorf("%s or %s not found in request", MetricTypeKey, MetricRequestTypeKey) } +func ParseMetricProcessInRole(jsonRet gjson.Result) (string, error) { + v := jsonRet.Get(MetricRequestProcessInRoleKey) + if v.Exists() { + return v.String(), nil + } + + return "", fmt.Errorf("%s not found in request", MetricRequestProcessInRoleKey) +} + func GetCollectionIDFromRequest(jsonReq gjson.Result) int64 { v := jsonReq.Get(MetricRequestParamCollectionIDKey) if !v.Exists() { diff --git a/pkg/util/metricsinfo/metric_request_test.go b/pkg/util/metricsinfo/metric_request_test.go index aff0add7c7..32e0f3dfd5 100644 --- a/pkg/util/metricsinfo/metric_request_test.go +++ b/pkg/util/metricsinfo/metric_request_test.go @@ -13,6 +13,7 @@ package metricsinfo import ( "encoding/json" + "fmt" "testing" "github.com/stretchr/testify/assert" @@ -20,6 +21,7 @@ import ( "go.uber.org/zap" "github.com/milvus-io/milvus/pkg/v2/log" + "github.com/milvus-io/milvus/pkg/v2/util/typeutil" ) func Test_ParseMetricType(t *testing.T) { @@ -79,3 +81,51 @@ func Test_ConstructRequestByMetricType(t *testing.T) { } } } + +func Test_ParseMetricProcessInRole(t *testing.T) { + tests := []struct { + name string + input string + expected string + wantErr bool + }{ + { + name: "Empty JSON", + input: "{}", + expected: "", + wantErr: true, + }, + { + name: "Valid ProcessRole value", + input: fmt.Sprintf(`{"%s": "%s"}`, MetricRequestProcessInRoleKey, typeutil.DataCoordRole), + expected: typeutil.DataCoordRole, + wantErr: false, + }, + { + name: "Valid ProcessRole with integer value", + input: fmt.Sprintf(`{"%s": 123}`, MetricRequestProcessInRoleKey), + expected: "123", + wantErr: false, + }, + { + name: "Invalid key name", + input: `{"invalid_key": "value"}`, + expected: "", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + jsonRet := gjson.Parse(tt.input) + result, err := ParseMetricProcessInRole(jsonRet) + + if tt.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.expected, result) + } + }) + } +}