xframe/component/agollo/protocol/http/request.go

139 lines
3.5 KiB
Go
Raw Normal View History

2024-10-12 12:55:20 +08:00
package http
import (
"fmt"
"io/ioutil"
"net/http"
"time"
"git.wishpal.cn/wishpal_ironfan/xframe/component/agollo/env"
"git.wishpal.cn/wishpal_ironfan/xframe/component/agollo/env/config"
"git.wishpal.cn/wishpal_ironfan/xframe/component/agollo/loadbalance"
"git.wishpal.cn/wishpal_ironfan/xframe/component/agollo/utils"
"git.wishpal.cn/wishpal_ironfan/xframe/component/logger"
"github.com/pkg/errors"
)
var (
//for on error retry
onErrorRetryInterval = 2 * time.Second //2s
connectTimeout = 1 * time.Second //1s
//max retries connect apollo
maxRetries = 5
)
// CallBack 请求回调函数
type CallBack struct {
SuccessCallBack func([]byte) (interface{}, error)
NotModifyCallBack func() error
}
// Request 建立网络请求
func Request(requestURL string, connectionConfig *env.ConnectConfig, callBack *CallBack) (interface{}, error) {
client := &http.Client{}
//如有设置自定义超时时间即使用
if connectionConfig != nil && connectionConfig.Timeout != 0 {
client.Timeout = connectionConfig.Timeout
} else {
client.Timeout = connectTimeout
}
retry := 0
var responseBody []byte
var err error
var res *http.Response
var retries = maxRetries
if connectionConfig != nil && !connectionConfig.IsRetry {
retries = 1
}
for {
retry++
if retry > retries {
break
}
res, err = client.Get(requestURL)
if res == nil || err != nil {
logger.Errorf("Connect Apollo Server Fail,url:%s,Error:%s", requestURL, err)
// if error then sleep
time.Sleep(onErrorRetryInterval)
continue
}
//not modified break
switch res.StatusCode {
case http.StatusOK:
responseBody, err = ioutil.ReadAll(res.Body)
if err != nil {
logger.Errorf("Connect Apollo Server Fail,url:%s,Error:", requestURL, err)
// if error then sleep
time.Sleep(onErrorRetryInterval)
continue
}
if callBack != nil && callBack.SuccessCallBack != nil {
return callBack.SuccessCallBack(responseBody)
}
return nil, nil
case http.StatusNotModified:
//log.Info("Config Not Modified, requestURL = %v", requestURL)
if callBack != nil && callBack.NotModifyCallBack != nil {
return nil, callBack.NotModifyCallBack()
}
return nil, nil
default:
logger.Errorf("Connect Apollo Server Fail,url:%s,StatusCode:%s", requestURL, res.StatusCode)
err = errors.New("connect Apollo Server Fail")
// if error then sleep
time.Sleep(onErrorRetryInterval)
continue
}
}
logger.Errorln("Over Max Retry Still Error,Error:", err)
if err != nil {
err = errors.New("over Max Retry Still Error")
}
return nil, err
}
// RequestRecovery 可以恢复的请求
func RequestRecovery(appConfig *config.AppConfig,
connectConfig *env.ConnectConfig,
callBack *CallBack) (interface{}, error) {
format := "%s%s"
var err error
var response interface{}
for {
host := loadBalance(appConfig)
if host == "" {
return nil, err
}
requestURL := fmt.Sprintf(format, host, connectConfig.URI)
response, err = Request(requestURL, connectConfig, callBack)
if err == nil {
return response, err
}
env.SetDownNode(host)
}
}
// 链接分为直连server和非直连。
// 非直连的情况下会通过配置中的ip访问到metaserver(类似于zookeeper)从metaserver中获取数据。只有当非直连失败的情况下才可能使用直连
func loadBalance(appConfig *config.AppConfig) string {
if !appConfig.IsConnectDirectly() {
return appConfig.GetHost()
}
serverInfo := loadbalance.GetLoadBalance().Load(env.GetServers())
if serverInfo == nil {
return utils.Empty
}
return serverInfo.HomepageURL
}