optimize reponse code and business code of measurement sub api

This commit is contained in:
douxu 2026-01-26 16:29:50 +08:00
parent fd2b202037
commit 1a1727adab
5 changed files with 94 additions and 117 deletions

View File

@ -16,6 +16,12 @@ var (
// ErrFoundTargetFailed define variable to returned when the specific database table cannot be identified using the provided token info. // ErrFoundTargetFailed define variable to returned when the specific database table cannot be identified using the provided token info.
ErrFoundTargetFailed = newError(40004, "found target table by token failed") ErrFoundTargetFailed = newError(40004, "found target table by token failed")
// ErrSubTargetRepeat define variable to indicates subscription target already exist in list
ErrSubTargetRepeat = newError(40005, "subscription target already exist in list")
// ErrSubTargetNotFound define variable to indicates can not find measurement by subscription target
ErrSubTargetNotFound = newError(40006, "found measuremnet by subscription target failed")
// ErrCancelSubTargetMissing define variable to indicates cancel a not exist subscription target
ErrCancelSubTargetMissing = newError(40007, "cancel a not exist subscription target")
// ErrDBQueryFailed define variable to represents a generic failure during a PostgreSQL SELECT or SCAN operation. // ErrDBQueryFailed define variable to represents a generic failure during a PostgreSQL SELECT or SCAN operation.
ErrDBQueryFailed = newError(50001, "query postgres database data failed") ErrDBQueryFailed = newError(50001, "query postgres database data failed")

View File

@ -1,17 +0,0 @@
// Package constants define constant variable
package constants
const (
// CodeSuccess define constant to indicates that the API was successfully processed
CodeSuccess = 20000
// CodeInvalidParamFailed define constant to indicates request parameter parsing failed
CodeInvalidParamFailed = 40001
// CodeDBQueryFailed define constant to indicates database query operation failed
CodeDBQueryFailed = 50001
// CodeDBUpdateailed define constant to indicates database update operation failed
CodeDBUpdateailed = 50002
// CodeRedisQueryFailed define constant to indicates redis query operation failed
CodeRedisQueryFailed = 60001
// CodeRedisUpdateFailed define constant to indicates redis update operation failed
CodeRedisUpdateFailed = 60002
)

View File

@ -0,0 +1,31 @@
// Package constants define constant variable
package constants
const (
// CodeSuccess define constant to indicates that the API was successfully processed
CodeSuccess = 20000
// CodeInvalidParamFailed define constant to indicates request parameter parsing failed
CodeInvalidParamFailed = 40001
// CodeFoundTargetFailed define variable to returned when the specific database table cannot be identified using the provided token info.
CodeFoundTargetFailed = 40004
// CodeSubTargetRepeat define variable to indicates subscription target already exist in list
CodeSubTargetRepeat = 40005
// CodeSubTargetNotFound define variable to indicates can not find measurement by subscription target
CodeSubTargetNotFound = 40006
// CodeCancelSubTargetMissing define variable to indicates cancel a not exist subscription target
CodeCancelSubTargetMissing = 40007
// CodeUpdateSubTargetMissing define variable to indicates update a not exist subscription target
CodeUpdateSubTargetMissing = 40008
// CodeAppendSubTargetMissing define variable to indicates append a not exist subscription target
CodeAppendSubTargetMissing = 40009
// CodeUnsupportSubOperation define variable to indicates append a not exist subscription target
CodeUnsupportSubOperation = 40010
// CodeDBQueryFailed define constant to indicates database query operation failed
CodeDBQueryFailed = 50001
// CodeDBUpdateailed define constant to indicates database update operation failed
CodeDBUpdateailed = 50002
// CodeRedisQueryFailed define constant to indicates redis query operation failed
CodeRedisQueryFailed = 60001
// CodeRedisUpdateFailed define constant to indicates redis update operation failed
CodeRedisUpdateFailed = 60002
)

View File

@ -5,7 +5,6 @@ import (
"context" "context"
"fmt" "fmt"
"maps" "maps"
"net/http"
"sync" "sync"
"modelRT/constants" "modelRT/constants"
@ -33,42 +32,42 @@ func init() {
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param request body network.RealTimeSubRequest true "量测节点实时数据订阅" // @Param request body network.RealTimeSubRequest true "量测节点实时数据订阅"
// @Success 200 {object} network.SuccessResponse{payload=network.RealTimeSubPayload} "订阅实时数据结果列表" // @Success 2000 {object} network.SuccessResponse{payload=network.RealTimeSubPayload} "订阅实时数据结果列表"
// //
// @Example 200 { // @Example 2000 {
// "code": 200, // "code": 2000,
// "msg": "success", // "msg": "process completed",
// "payload": { // "payload": {
// "targets": [ // "targets": [
// { // {
// "id": "grid1.zone1.station1.ns1.tag1.bay.I11_C_rms", // "id": "grid1.zone1.station1.ns1.tag1.bay.I11_C_rms",
// "code": "1001", // "code": "20000",
// "msg": "subscription success" // "msg": "subscription success"
// }, // },
// { // {
// "id": "grid1.zone1.station1.ns1.tag1.bay.I11_B_rms", // "id": "grid1.zone1.station1.ns1.tag1.bay.I11_B_rms",
// "code": "1002", // "code": "20000",
// "msg": "subscription failed" // "msg": "subscription failed"
// } // }
// ] // ]
// } // }
// } // }
// //
// @Failure 400 {object} network.FailureResponse{payload=network.RealTimeSubPayload} "订阅实时数据结果列表" // @Failure 3000 {object} network.FailureResponse{payload=network.RealTimeSubPayload} "订阅实时数据结果列表"
// //
// @Example 400 { // @Example 3000 {
// "code": 400, // "code": 3000,
// "msg": "failed to get recommend data from redis", // "msg": "process completed with partial failures",
// "payload": { // "payload": {
// "targets": [ // "targets": [
// { // {
// "id": "grid1.zone1.station1.ns1.tag1.bay.I11_A_rms", // "id": "grid1.zone1.station1.ns1.tag1.bay.I11_A_rms",
// "code": "1002", // "code": "40005",
// "msg": "subscription failed" // "msg": "subscription failed"
// }, // },
// { // {
// "id": "grid1.zone1.station1.ns1.tag1.bay.I11_B_rms", // "id": "grid1.zone1.station1.ns1.tag1.bay.I11_B_rms",
// "code": "1002", // "code": "50001",
// "msg": "subscription failed" // "msg": "subscription failed"
// } // }
// ] // ]
@ -83,10 +82,7 @@ func RealTimeSubHandler(c *gin.Context) {
if err := c.ShouldBindJSON(&request); err != nil { if err := c.ShouldBindJSON(&request); err != nil {
logger.Error(c, "failed to unmarshal real time query request", "error", err) logger.Error(c, "failed to unmarshal real time query request", "error", err)
c.JSON(http.StatusOK, network.FailureResponse{ renderRespFailure(c, constants.RespCodeInvalidParams, err.Error(), nil)
Code: http.StatusBadRequest,
Msg: err.Error(),
})
return return
} }
@ -95,10 +91,7 @@ func RealTimeSubHandler(c *gin.Context) {
id, err := uuid.NewV4() id, err := uuid.NewV4()
if err != nil { if err != nil {
logger.Error(c, "failed to generate client id", "error", err) logger.Error(c, "failed to generate client id", "error", err)
c.JSON(http.StatusOK, network.FailureResponse{ renderRespFailure(c, constants.RespCodeInvalidParams, err.Error(), nil)
Code: http.StatusBadRequest,
Msg: err.Error(),
})
return return
} }
clientID = id.String() clientID = id.String()
@ -123,110 +116,74 @@ func RealTimeSubHandler(c *gin.Context) {
results, err := globalSubState.CreateConfig(c, tx, clientID, request.Measurements) results, err := globalSubState.CreateConfig(c, tx, clientID, request.Measurements)
if err != nil { if err != nil {
logger.Error(c, "create real time data subscription config failed", "error", err) logger.Error(c, "create real time data subscription config failed", "error", err)
c.JSON(http.StatusOK, network.FailureResponse{ renderRespFailure(c, constants.RespCodeFailed, err.Error(), network.RealTimeSubPayload{
Code: http.StatusBadRequest, ClientID: clientID,
Msg: err.Error(), TargetResults: results,
Payload: network.RealTimeSubPayload{
ClientID: clientID,
TargetResults: results,
},
}) })
return return
} }
c.JSON(http.StatusOK, network.SuccessResponse{ renderRespSuccess(c, constants.RespCodeSuccess, "process completed", network.RealTimeSubPayload{
Code: http.StatusOK, ClientID: clientID,
Msg: "success", TargetResults: results,
Payload: network.RealTimeSubPayload{
ClientID: clientID,
TargetResults: results,
},
}) })
return return
case constants.SubStopAction: case constants.SubStopAction:
results, err := globalSubState.RemoveTargets(c, clientID, request.Measurements) results, err := globalSubState.RemoveTargets(c, clientID, request.Measurements)
if err != nil { if err != nil {
logger.Error(c, "remove target to real time data subscription config failed", "error", err) logger.Error(c, "remove target to real time data subscription config failed", "error", err)
c.JSON(http.StatusOK, network.FailureResponse{ renderRespFailure(c, constants.RespCodeFailed, err.Error(), network.RealTimeSubPayload{
Code: http.StatusBadRequest, ClientID: clientID,
Msg: err.Error(), TargetResults: results,
Payload: network.RealTimeSubPayload{
ClientID: clientID,
TargetResults: results,
},
}) })
return return
} }
c.JSON(http.StatusOK, network.SuccessResponse{ renderRespSuccess(c, constants.RespCodeSuccess, "success", network.RealTimeSubPayload{
Code: http.StatusOK, ClientID: clientID,
Msg: "success", TargetResults: results,
Payload: network.RealTimeSubPayload{
ClientID: clientID,
TargetResults: results,
},
}) })
return return
case constants.SubAppendAction: case constants.SubAppendAction:
results, err := globalSubState.AppendTargets(c, tx, clientID, request.Measurements) results, err := globalSubState.AppendTargets(c, tx, clientID, request.Measurements)
if err != nil { if err != nil {
logger.Error(c, "append target to real time data subscription config failed", "error", err) logger.Error(c, "append target to real time data subscription config failed", "error", err)
c.JSON(http.StatusOK, network.FailureResponse{ renderRespFailure(c, constants.RespCodeFailed, err.Error(), network.RealTimeSubPayload{
Code: http.StatusBadRequest, ClientID: clientID,
Msg: err.Error(), TargetResults: results,
Payload: network.RealTimeSubPayload{
ClientID: clientID,
TargetResults: results,
},
}) })
return return
} }
c.JSON(http.StatusOK, network.SuccessResponse{ renderRespSuccess(c, constants.RespCodeSuccess, "success", network.RealTimeSubPayload{
Code: http.StatusOK, ClientID: clientID,
Msg: "success", TargetResults: results,
Payload: network.RealTimeSubPayload{
ClientID: clientID,
TargetResults: results,
},
}) })
return return
case constants.SubUpdateAction: case constants.SubUpdateAction:
results, err := globalSubState.UpdateTargets(c, tx, clientID, request.Measurements) results, err := globalSubState.UpdateTargets(c, tx, clientID, request.Measurements)
if err != nil { if err != nil {
logger.Error(c, "update target to real time data subscription config failed", "error", err) logger.Error(c, "update target to real time data subscription config failed", "error", err)
c.JSON(http.StatusOK, network.FailureResponse{ renderRespFailure(c, constants.RespCodeFailed, err.Error(), network.RealTimeSubPayload{
Code: http.StatusBadRequest, ClientID: clientID,
Msg: err.Error(), TargetResults: results,
Payload: network.RealTimeSubPayload{
ClientID: clientID,
TargetResults: results,
},
}) })
return return
} }
c.JSON(http.StatusOK, network.SuccessResponse{ renderRespSuccess(c, constants.RespCodeSuccess, "success", network.RealTimeSubPayload{
Code: http.StatusOK, ClientID: clientID,
Msg: "success", TargetResults: results,
Payload: network.RealTimeSubPayload{
ClientID: clientID,
TargetResults: results,
},
}) })
return return
default: default:
err := fmt.Errorf("%w: request action is %s", constants.ErrUnsupportedSubAction, request.Action) err := fmt.Errorf("%w: request action is %s", constants.ErrUnsupportedSubAction, request.Action)
logger.Error(c, "unsupported action of real time data subscription request", "error", err) logger.Error(c, "unsupported action of real time data subscription request", "error", err)
requestTargetsCount := processRealTimeRequestCount(request.Measurements) requestTargetsCount := processRealTimeRequestCount(request.Measurements)
results := processRealTimeRequestTargets(request.Measurements, requestTargetsCount, err) results := processRealTimeRequestTargets(request.Measurements, requestTargetsCount, constants.CodeUnsupportSubOperation, err)
c.JSON(http.StatusOK, network.FailureResponse{ renderRespFailure(c, constants.RespCodeInvalidParams, err.Error(), network.RealTimeSubPayload{
Code: http.StatusBadRequest, ClientID: clientID,
Msg: err.Error(), TargetResults: results,
Payload: network.RealTimeSubPayload{
ClientID: clientID,
TargetResults: results,
},
}) })
return return
} }
@ -283,12 +240,12 @@ func processAndValidateTargetsForStart(ctx context.Context, tx *gorm.DB, measure
targetModel, err := database.ParseDataIdentifierToken(ctx, tx, target) targetModel, err := database.ParseDataIdentifierToken(ctx, tx, target)
if err != nil { if err != nil {
logger.Error(ctx, "parse data indentity token failed", "error", err, "identity_token", target) logger.Error(ctx, "parse data indentity token failed", "error", err, "identity_token", target)
targetResult.Code = constants.SubFailedCode targetResult.Code = constants.CodeFoundTargetFailed
targetResult.Msg = fmt.Sprintf("%s: %s", constants.SubFailedMsg, err.Error()) targetResult.Msg = fmt.Sprintf("%s: %s", constants.SubFailedMsg, err.Error())
targetProcessResults = append(targetProcessResults, targetResult) targetProcessResults = append(targetProcessResults, targetResult)
continue continue
} }
targetResult.Code = constants.SubSuccessCode targetResult.Code = constants.CodeSuccess
targetResult.Msg = constants.SubSuccessMsg targetResult.Msg = constants.SubSuccessMsg
targetProcessResults = append(targetProcessResults, targetResult) targetProcessResults = append(targetProcessResults, targetResult)
successfulTargets = append(successfulTargets, target) successfulTargets = append(successfulTargets, target)
@ -327,7 +284,7 @@ func processAndValidateTargetsForUpdate(ctx context.Context, tx *gorm.DB, config
if _, exist := config.targetContext[target]; !exist { if _, exist := config.targetContext[target]; !exist {
err := fmt.Errorf("target %s does not exists in subscription list", target) err := fmt.Errorf("target %s does not exists in subscription list", target)
logger.Error(ctx, "update target does not exist in subscription list", "error", err, "target", target) logger.Error(ctx, "update target does not exist in subscription list", "error", err, "target", target)
targetResult.Code = constants.UpdateSubFailedCode targetResult.Code = constants.CodeUpdateSubTargetMissing
targetResult.Msg = fmt.Sprintf("%s: %s", constants.UpdateSubFailedMsg, err.Error()) targetResult.Msg = fmt.Sprintf("%s: %s", constants.UpdateSubFailedMsg, err.Error())
targetProcessResults = append(targetProcessResults, targetResult) targetProcessResults = append(targetProcessResults, targetResult)
continue continue
@ -336,13 +293,13 @@ func processAndValidateTargetsForUpdate(ctx context.Context, tx *gorm.DB, config
targetModel, err := database.ParseDataIdentifierToken(ctx, tx, target) targetModel, err := database.ParseDataIdentifierToken(ctx, tx, target)
if err != nil { if err != nil {
logger.Error(ctx, "parse data indentity token failed", "error", err, "identity_token", target) logger.Error(ctx, "parse data indentity token failed", "error", err, "identity_token", target)
targetResult.Code = constants.UpdateSubFailedCode targetResult.Code = constants.CodeDBQueryFailed
targetResult.Msg = fmt.Sprintf("%s: %s", constants.UpdateSubFailedMsg, err.Error()) targetResult.Msg = fmt.Sprintf("%s: %s", constants.UpdateSubFailedMsg, err.Error())
targetProcessResults = append(targetProcessResults, targetResult) targetProcessResults = append(targetProcessResults, targetResult)
continue continue
} }
targetResult.Code = constants.UpdateSubSuccessCode targetResult.Code = constants.CodeSuccess
targetResult.Msg = constants.UpdateSubSuccessMsg targetResult.Msg = constants.UpdateSubSuccessMsg
targetProcessResults = append(targetProcessResults, targetResult) targetProcessResults = append(targetProcessResults, targetResult)
successfulTargets = append(successfulTargets, target) successfulTargets = append(successfulTargets, target)
@ -473,7 +430,7 @@ func (s *SharedSubState) AppendTargets(ctx context.Context, tx *gorm.DB, clientI
if !exist { if !exist {
err := fmt.Errorf("clientID %s not found. use CreateConfig to start a new config", clientID) err := fmt.Errorf("clientID %s not found. use CreateConfig to start a new config", clientID)
logger.Error(ctx, "clientID not found. use CreateConfig to start a new config", "error", err) logger.Error(ctx, "clientID not found. use CreateConfig to start a new config", "error", err)
return processRealTimeRequestTargets(measurements, requestTargetsCount, err), err return processRealTimeRequestTargets(measurements, requestTargetsCount, constants.CodeAppendSubTargetMissing, err), err
} }
targetProcessResults, successfulTargets, newMeasMap, newMeasContextMap := processAndValidateTargetsForStart(ctx, tx, measurements, requestTargetsCount) targetProcessResults, successfulTargets, newMeasMap, newMeasContextMap := processAndValidateTargetsForStart(ctx, tx, measurements, requestTargetsCount)
@ -507,7 +464,7 @@ func filterAndDeduplicateRepeatTargets(resultsSlice []network.TargetResult, idsS
for index := range resultsSlice { for index := range resultsSlice {
if _, isTarget := set[resultsSlice[index].ID]; isTarget { if _, isTarget := set[resultsSlice[index].ID]; isTarget {
resultsSlice[index].Code = constants.SubRepeatCode resultsSlice[index].Code = constants.CodeSubTargetRepeat
resultsSlice[index].Msg = constants.SubRepeatMsg resultsSlice[index].Msg = constants.SubRepeatMsg
} }
} }
@ -575,7 +532,7 @@ func (s *SharedSubState) RemoveTargets(ctx context.Context, clientID string, mea
s.globalMutex.RUnlock() s.globalMutex.RUnlock()
err := fmt.Errorf("clientID %s not found", clientID) err := fmt.Errorf("clientID %s not found", clientID)
logger.Error(ctx, "clientID not found in remove targets operation", "error", err) logger.Error(ctx, "clientID not found in remove targets operation", "error", err)
return processRealTimeRequestTargets(measurements, requestTargetsCount, err), err return processRealTimeRequestTargets(measurements, requestTargetsCount, constants.CodeCancelSubTargetMissing, err), err
} }
s.globalMutex.RUnlock() s.globalMutex.RUnlock()
@ -595,7 +552,7 @@ func (s *SharedSubState) RemoveTargets(ctx context.Context, clientID string, mea
for _, target := range measTargets { for _, target := range measTargets {
targetResult := network.TargetResult{ targetResult := network.TargetResult{
ID: target, ID: target,
Code: constants.CancelSubFailedCode, Code: constants.CodeCancelSubTargetMissing,
Msg: constants.CancelSubFailedMsg, Msg: constants.CancelSubFailedMsg,
} }
targetProcessResults = append(targetProcessResults, targetResult) targetProcessResults = append(targetProcessResults, targetResult)
@ -616,7 +573,7 @@ func (s *SharedSubState) RemoveTargets(ctx context.Context, clientID string, mea
transportTargets.Targets = append(transportTargets.Targets, existingTarget) transportTargets.Targets = append(transportTargets.Targets, existingTarget)
targetResult := network.TargetResult{ targetResult := network.TargetResult{
ID: existingTarget, ID: existingTarget,
Code: constants.CancelSubSuccessCode, Code: constants.CodeSuccess,
Msg: constants.CancelSubSuccessMsg, Msg: constants.CancelSubSuccessMsg,
} }
targetProcessResults = append(targetProcessResults, targetResult) targetProcessResults = append(targetProcessResults, targetResult)
@ -639,7 +596,7 @@ func (s *SharedSubState) RemoveTargets(ctx context.Context, clientID string, mea
for target := range targetsToRemoveMap { for target := range targetsToRemoveMap {
targetResult := network.TargetResult{ targetResult := network.TargetResult{
ID: target, ID: target,
Code: constants.CancelSubFailedCode, Code: constants.CodeCancelSubTargetMissing,
Msg: fmt.Sprintf("%s: %s", constants.SubFailedMsg, err.Error()), Msg: fmt.Sprintf("%s: %s", constants.SubFailedMsg, err.Error()),
} }
targetProcessResults = append(targetProcessResults, targetResult) targetProcessResults = append(targetProcessResults, targetResult)
@ -673,7 +630,7 @@ func (s *SharedSubState) UpdateTargets(ctx context.Context, tx *gorm.DB, clientI
s.globalMutex.RUnlock() s.globalMutex.RUnlock()
err := fmt.Errorf("clientID %s not found", clientID) err := fmt.Errorf("clientID %s not found", clientID)
logger.Error(ctx, "clientID not found in remove targets operation", "error", err) logger.Error(ctx, "clientID not found in remove targets operation", "error", err)
return processRealTimeRequestTargets(measurements, requestTargetsCount, err), err return processRealTimeRequestTargets(measurements, requestTargetsCount, constants.CodeUpdateSubTargetMissing, err), err
} }
targetProcessResults, successfulTargets, newMeasMap, newMeasContextMap := processAndValidateTargetsForUpdate(ctx, tx, config, measurements, requestTargetsCount) targetProcessResults, successfulTargets, newMeasMap, newMeasContextMap := processAndValidateTargetsForUpdate(ctx, tx, config, measurements, requestTargetsCount)
@ -722,13 +679,13 @@ func processRealTimeRequestCount(measurements []network.RealTimeMeasurementItem)
return totalTargetsCount return totalTargetsCount
} }
func processRealTimeRequestTargets(measurements []network.RealTimeMeasurementItem, targetCount int, err error) []network.TargetResult { func processRealTimeRequestTargets(measurements []network.RealTimeMeasurementItem, targetCount int, businessCode int, err error) []network.TargetResult {
targetProcessResults := make([]network.TargetResult, 0, targetCount) targetProcessResults := make([]network.TargetResult, 0, targetCount)
for _, measurementItem := range measurements { for _, measurementItem := range measurements {
for _, target := range measurementItem.Targets { for _, target := range measurementItem.Targets {
var targetResult network.TargetResult var targetResult network.TargetResult
targetResult.ID = target targetResult.ID = target
targetResult.Code = constants.SubFailedCode targetResult.Code = businessCode
targetResult.Msg = fmt.Sprintf("%s: %s", constants.SubFailedMsg, err.Error()) targetResult.Msg = fmt.Sprintf("%s: %s", constants.SubFailedMsg, err.Error())
targetProcessResults = append(targetProcessResults, targetResult) targetProcessResults = append(targetProcessResults, targetResult)
} }

View File

@ -26,7 +26,7 @@ type MeasurementRecommendPayload struct {
// TargetResult define struct of target item in real time data subscription response payload // TargetResult define struct of target item in real time data subscription response payload
type TargetResult struct { type TargetResult struct {
ID string `json:"id" example:"grid1.zone1.station1.ns1.tag1.transformfeeder1_220.I_A_rms"` ID string `json:"id" example:"grid1.zone1.station1.ns1.tag1.transformfeeder1_220.I_A_rms"`
Code string `json:"code" example:"1001"` Code int `json:"code" example:"20000"`
Msg string `json:"msg" example:"subscription success"` Msg string `json:"msg" example:"subscription success"`
} }