规划mesh请求的框架结构, 细节待完善
This commit is contained in:
parent
93a855d1ae
commit
d9da985da5
@ -1,76 +0,0 @@
|
|||||||
// Package define ...
|
|
||||||
//
|
|
||||||
// Description : define ...
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 2025-03-28 14:12
|
|
||||||
package define
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.zhangdeman.cn/zhangdeman/consts"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MeshRequestConfig 聚合请求
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 14:14 2025/3/28
|
|
||||||
type MeshRequestConfig struct {
|
|
||||||
CommonParam map[string]any `json:"common_param"` // 公共参数
|
|
||||||
Group [][]MeshRequestConfigGroupItem `json:"group"` // 请求分组
|
|
||||||
ResultRule []MeshRequestConfigResultRule `json:"result_rule"` // 结果提取规则, 多个接口的结果构造成一个返回结果
|
|
||||||
Receiver any `json:"-"` // 整体请求结果数据接收的指针
|
|
||||||
}
|
|
||||||
|
|
||||||
// MeshRequestConfigGroupItem 分组请求每一项的结构
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 14:16 2025/3/28
|
|
||||||
type MeshRequestConfigGroupItem struct {
|
|
||||||
Alias string `json:"alias"` // 请求别名
|
|
||||||
ParamRuleList []MeshRequestConfigGroupItemParamRule `json:"param_rule_list"` // 参数规则列表
|
|
||||||
RequestCfg Request `json:"request_cfg"` // 请求配置
|
|
||||||
Condition any `json:"condition"` // TODO: 请求条件, 特定条件下不执行当前请求
|
|
||||||
}
|
|
||||||
|
|
||||||
// MeshRequestConfigGroupItemParamRule 参数提取规则
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 14:23 2025/3/28
|
|
||||||
type MeshRequestConfigGroupItemParamRule struct {
|
|
||||||
Location consts.RequestDataLocation `json:"location"` // 参数位置
|
|
||||||
Path string `json:"path"` // 参数设置的路径
|
|
||||||
Type consts.DataType `json:"type"` // 参数类型
|
|
||||||
SourceAlias string `json:"source_alias"` // 数据源请求别名 __COMMON__ 代表从公共参数读取数据
|
|
||||||
SourceResultPath string `json:"source_result_path"` // 数据源数据, 从结果中获取的路径
|
|
||||||
}
|
|
||||||
|
|
||||||
// MeshRequestConfigResultRule 返回值构建规则
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 14:28 2025/3/28
|
|
||||||
type MeshRequestConfigResultRule struct {
|
|
||||||
RequestAlias string `json:"request_alias"` // 请求别名
|
|
||||||
RequestResultLocation consts.ResponseDataLocation `json:"request_result_location"` // 请求结果位置
|
|
||||||
RequestResultPath string `json:"request_result_path"` // 请求结果路径
|
|
||||||
Location consts.ResponseDataLocation `json:"location"` // 返回值位置
|
|
||||||
DataPath string `json:"data_path"` // 返回值的路径
|
|
||||||
DataType consts.DataType `json:"data_type"` // 返回值类型
|
|
||||||
}
|
|
||||||
|
|
||||||
// MeshResponse 聚合请求响应结果
|
|
||||||
//
|
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
|
||||||
//
|
|
||||||
// Date : 14:40 2025/3/28
|
|
||||||
type MeshResponse struct {
|
|
||||||
Raw []byte `json:"raw"` // 返回结果的raw数据(按照result_rule格式化后的结果)
|
|
||||||
DataMap map[string]any `json:"data_map"` // 返回结果的map格式(按照result_rule格式化后的结果)
|
|
||||||
AliasResultTable map[string]Response `json:"alias_result_table"` // 每一个请求的返回结果 key: 请求别名 value: 请求返回数据
|
|
||||||
Lock *sync.RWMutex `json:"-"` // 数据锁, public, 外部拿到结果需要做一席并发读写操作, 可以直接服用这把所
|
|
||||||
}
|
|
@ -7,12 +7,15 @@
|
|||||||
// Date : 2024-05-24 17:09
|
// Date : 2024-05-24 17:09
|
||||||
package define
|
package define
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
// Request 请求配置
|
// Request 请求配置
|
||||||
//
|
//
|
||||||
// Author : go_developer@163.com<白茶清欢>
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
//
|
//
|
||||||
// Date : 17:10 2024/5/24
|
// Date : 17:10 2024/5/24
|
||||||
type Request struct {
|
type Request struct {
|
||||||
|
Ctx context.Context `json:"-"` // 请求上下文
|
||||||
PathParam map[string]string `json:"path_param"` // 替换url中的占位符
|
PathParam map[string]string `json:"path_param"` // 替换url中的占位符
|
||||||
Body map[string]any `json:"body"` // 请求Body
|
Body map[string]any `json:"body"` // 请求Body
|
||||||
Header map[string]string `json:"header"` // 请求Header
|
Header map[string]string `json:"header"` // 请求Header
|
||||||
|
103
httpclient/mesh/define.go
Normal file
103
httpclient/mesh/define.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// Package mesh ...
|
||||||
|
//
|
||||||
|
// Description : define ...
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 2025-03-28 14:12
|
||||||
|
package mesh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/consts"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/network/httpclient/cache"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/network/httpclient/define"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RequestConfig 聚合请求
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 14:14 2025/3/28
|
||||||
|
type RequestConfig struct {
|
||||||
|
Ctx context.Context `json:"-"` // 上下文
|
||||||
|
CommonParam map[string]any `json:"common_param"` // 公共参数
|
||||||
|
Group [][]*RequestConfigGroupItem `json:"group"` // 请求分组
|
||||||
|
ResultRule []*RequestConfigResultRule `json:"result_rule"` // 结果提取规则, 多个接口的结果构造成一个返回结果
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestConfigGroupItem 分组请求每一项的结构
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 14:16 2025/3/28
|
||||||
|
type RequestConfigGroupItem struct {
|
||||||
|
Alias string `json:"alias"` // 请求别名
|
||||||
|
ParamRuleList []*RequestConfigGroupItemParamRule `json:"param_rule_list"` // 参数规则列表
|
||||||
|
RequestCfg *define.Request `json:"request_cfg"` // 请求配置
|
||||||
|
FailBehavior *RequestConfigGroupItemFailBehavior `json:"fail_behavior"` // 失败的行为, 不配置, 默认失败break
|
||||||
|
FinalFailureAllow bool `json:"final_failure_allow"` // 已经确定当前请求是最终失败了,当前请求是否允许执行
|
||||||
|
CacheInstance cache.ICache `json:"-"` // 数据缓存实例
|
||||||
|
Condition any `json:"condition"` // TODO: 请求条件, 特定条件下不执行当前请求
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestConfigGroupItemFailBehavior 失败的行为
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 15:51 2025/3/28
|
||||||
|
type RequestConfigGroupItemFailBehavior struct {
|
||||||
|
Action string `json:"action"` // 请求失败的行为: continue: 继续执行下一个请求, break: 停止执行后续请求
|
||||||
|
FinalFailure bool `json:"final_failure"` // 是否作为最终失败: action = break时, 无论外部是什么值, 永远为true, 当 action = continue时, 该值由外部传入, 原因: 当前接口失败, 可能还需要调用一些后续接口做些逻辑.
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestConfigGroupItemParamRule 参数提取规则
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 14:23 2025/3/28
|
||||||
|
type RequestConfigGroupItemParamRule struct {
|
||||||
|
Location consts.RequestDataLocation `json:"location"` // 参数位置
|
||||||
|
Path string `json:"path"` // 参数设置的路径
|
||||||
|
Type consts.DataType `json:"type"` // 参数类型
|
||||||
|
SourceAlias string `json:"source_alias"` // 数据源请求别名 __COMMON__ 代表从公共参数读取数据
|
||||||
|
SourceResultPath string `json:"source_result_path"` // 数据源数据, 从结果中获取的路径
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestConfigResultRule 返回值构建规则
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 14:28 2025/3/28
|
||||||
|
type RequestConfigResultRule struct {
|
||||||
|
RequestAlias string `json:"request_alias"` // 请求别名
|
||||||
|
RequestResultLocation consts.ResponseDataLocation `json:"request_result_location"` // 请求结果位置
|
||||||
|
RequestResultPath string `json:"request_result_path"` // 请求结果路径
|
||||||
|
Location consts.ResponseDataLocation `json:"location"` // 返回值位置
|
||||||
|
DataPath string `json:"data_path"` // 返回值的路径
|
||||||
|
DataType consts.DataType `json:"data_type"` // 返回值类型
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response 聚合请求响应结果
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 14:40 2025/3/28
|
||||||
|
type Response struct {
|
||||||
|
FinalFailure bool `json:"final_failure"` // 是否最终失败
|
||||||
|
FailureApiAlias string `json:"failure_api_alias"` // 导致最终失败的接口别名
|
||||||
|
IsSuccess bool `json:"is_success"` // 请求是否成功
|
||||||
|
ErrorCode string `json:"error_code"` // 错误码
|
||||||
|
ErrorMessage string `json:"error_message"` // 错误信息
|
||||||
|
FailApiAlias []string `json:"fail_api_alias"` // 失败的接口别名
|
||||||
|
Raw []byte `json:"raw"` // 返回结果的raw数据(按照result_rule格式化后的结果)
|
||||||
|
DataMap map[string]any `json:"data_map"` // 返回结果的map格式(按照result_rule格式化后的结果)
|
||||||
|
AliasResultTable map[string]*Response `json:"alias_result_table"` // 每一个请求的返回结果 key: 请求别名 value: 请求返回数据
|
||||||
|
Lock *sync.RWMutex `json:"-"` // 数据锁, public, 外部拿到结果需要做一席并发读写操作, 可以直接复用这把锁
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
FailBehaviorContinue = "continue" // 失败后继续请求
|
||||||
|
FailBehaviorError = "error" // 失败后终止请求
|
||||||
|
)
|
@ -6,3 +6,109 @@
|
|||||||
//
|
//
|
||||||
// Date : 2025-03-28 14:11
|
// Date : 2025-03-28 14:11
|
||||||
package mesh
|
package mesh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.zhangdeman.cn/zhangdeman/network/httpclient"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Request(req *RequestConfig, receiver any) *Response {
|
||||||
|
if nil == req.Ctx {
|
||||||
|
req.Ctx = context.Background()
|
||||||
|
}
|
||||||
|
c := &client{
|
||||||
|
resp: &Response{
|
||||||
|
IsSuccess: false,
|
||||||
|
ErrorCode: "",
|
||||||
|
ErrorMessage: "",
|
||||||
|
Raw: nil,
|
||||||
|
DataMap: nil,
|
||||||
|
AliasResultTable: make(map[string]*Response),
|
||||||
|
Lock: &sync.RWMutex{},
|
||||||
|
},
|
||||||
|
reqCfg: req,
|
||||||
|
receiver: receiver,
|
||||||
|
}
|
||||||
|
return c.Request()
|
||||||
|
}
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
ctx context.Context
|
||||||
|
resp *Response
|
||||||
|
reqCfg *RequestConfig
|
||||||
|
receiver any
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) Request() *Response {
|
||||||
|
for _, itemGroup := range c.reqCfg.Group {
|
||||||
|
if !c.doRequest(itemGroup) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// doRequest 返回是否继续
|
||||||
|
//
|
||||||
|
// Author : go_developer@163.com<白茶清欢>
|
||||||
|
//
|
||||||
|
// Date : 15:30 2025/3/28
|
||||||
|
func (c *client) doRequest(apiList []*RequestConfigGroupItem) bool {
|
||||||
|
if len(apiList) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 初始化请求配置, 并获取 http client 实例
|
||||||
|
httpClientList := make([]*httpclient.HttpClient, 0)
|
||||||
|
for _, apiCfg := range apiList {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
httpClient *httpclient.HttpClient
|
||||||
|
)
|
||||||
|
// 初始化一下请求
|
||||||
|
c.initApiCfg(apiCfg)
|
||||||
|
if httpClient, err = httpclient.NewHttpClient(apiCfg.RequestCfg, apiCfg.CacheInstance); nil != err {
|
||||||
|
// 此处获取客户端实例即发生异常, 忽略一切配置, 直接作为全局失败, 后续也不请求了
|
||||||
|
c.resp.ErrorCode = "-500"
|
||||||
|
c.resp.ErrorMessage = err.Error()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
httpClientList = append(httpClientList, httpClient)
|
||||||
|
}
|
||||||
|
isContinue := true
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
for idx, apiCfg := range apiList {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(clientIdx int, apiCfg *RequestConfigGroupItem) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); nil != err {
|
||||||
|
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
// TODO : 判断是否已经是最终失败
|
||||||
|
resp := httpClientList[clientIdx].Request()
|
||||||
|
c.resp.Lock.Lock()
|
||||||
|
defer c.resp.Lock.Unlock()
|
||||||
|
if !resp.IsSuccess {
|
||||||
|
}
|
||||||
|
}(idx, apiCfg)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
return isContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) initApiCfg(apiCfg *RequestConfigGroupItem) {
|
||||||
|
if apiCfg.FailBehavior == nil {
|
||||||
|
apiCfg.FailBehavior = &RequestConfigGroupItemFailBehavior{
|
||||||
|
Action: FailBehaviorError, // 默认失败终止请求
|
||||||
|
FinalFailure: true, // 默认一旦失败,则争个整个失败
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if apiCfg.FailBehavior.Action == FailBehaviorError {
|
||||||
|
// 配置了请求失败则报错, 一定是导致结果最终失败
|
||||||
|
apiCfg.FailBehavior.FinalFailure = true
|
||||||
|
}
|
||||||
|
// 每一个请求有独立的context
|
||||||
|
apiCfg.RequestCfg.Ctx = context.WithValue(c.reqCfg.Ctx, "alias", apiCfg.Alias)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user