Skip to content

Commit

Permalink
Merge pull request #297 from larry4xie/failfast-http-err-status
Browse files Browse the repository at this point in the history
Failfast for explicit error http request instead of retrying (#296)
  • Loading branch information
mergify[bot] authored Dec 30, 2023
2 parents 69e0a6d + 8b7b49c commit f147bf5
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 16 deletions.
30 changes: 23 additions & 7 deletions component/remote/async_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func initMockNotifyAndConfigServerWithTwoErrResponse() *httptest.Server {
return runMockConfigServer(handlerMap, onlynormaltworesponse)
}

//run mock config server
// run mock config server
func runMockConfigServer(handlerMap map[string]func(http.ResponseWriter, *http.Request),
notifyHandler func(http.ResponseWriter, *http.Request)) *httptest.Server {
appConfig := env.InitFileConfig()
Expand Down Expand Up @@ -177,11 +177,11 @@ func initNotifications() *config.AppConfig {
return appConfig
}

//Error response
//will hold 5s and keep response 404
func runErrorResponse() *httptest.Server {
// Error response with status and body
func runErrorResponse(status int, body []byte) *httptest.Server {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
w.WriteHeader(status)
_, _ = w.Write(body)
}))

return ts
Expand Down Expand Up @@ -281,10 +281,26 @@ func TestGetRemoteConfig(t *testing.T) {
}

func TestErrorGetRemoteConfig(t *testing.T) {
tests := []struct {
name string
status int
errContained string
}{
{name: "500", status: http.StatusInternalServerError, errContained: "over Max Retry Still Error"},
{name: "404", status: http.StatusNotFound, errContained: "Connect Apollo Server Fail"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
testErrorGetRemoteConfig(t, tt.status, tt.errContained)
})
}
}

func testErrorGetRemoteConfig(t *testing.T, status int, errContained string) {
//clear
initNotifications()
appConfig := initNotifications()
server1 := runErrorResponse()
server1 := runErrorResponse(status, nil)
appConfig.IP = server1.URL
server.SetNextTryConnTime(appConfig.GetHost(), 0)

Expand All @@ -303,7 +319,7 @@ func TestErrorGetRemoteConfig(t *testing.T) {
t.Log("remoteConfigs:", remoteConfigs)
t.Log("remoteConfigs size:", len(remoteConfigs))

Assert(t, "over Max Retry Still Error", Equal(err.Error()))
Assert(t, err.Error(), StartWith(errContained))
}

func TestCreateApolloConfigWithJson(t *testing.T) {
Expand Down
9 changes: 6 additions & 3 deletions protocol/http/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ func getDefaultTransport(insecureSkipVerify bool) *http.Transport {
return defaultTransport
}

//CallBack 请求回调函数
// CallBack 请求回调函数
type CallBack struct {
SuccessCallBack func([]byte, CallBack) (interface{}, error)
NotModifyCallBack func() error
AppConfigFunc func() config.AppConfig
Namespace string
}

//Request 建立网络请求
// Request 建立网络请求
func Request(requestURL string, connectionConfig *env.ConnectConfig, callBack *CallBack) (interface{}, error) {
client := &http.Client{}
//如有设置自定义超时时间即使用
Expand Down Expand Up @@ -175,6 +175,9 @@ func Request(requestURL string, connectionConfig *env.ConnectConfig, callBack *C
return nil, callBack.NotModifyCallBack()
}
return nil, nil
case http.StatusBadRequest, http.StatusUnauthorized, http.StatusNotFound, http.StatusMethodNotAllowed:
log.Errorf("Connect Apollo Server Fail, url:%s, StatusCode:%d", requestURL, res.StatusCode)
return nil, errors.New(fmt.Sprintf("Connect Apollo Server Fail, StatusCode:%d", res.StatusCode))
default:
log.Errorf("Connect Apollo Server Fail, url:%s, StatusCode:%d", requestURL, res.StatusCode)
// if error then sleep
Expand All @@ -190,7 +193,7 @@ func Request(requestURL string, connectionConfig *env.ConnectConfig, callBack *C
return nil, err
}

//RequestRecovery 可以恢复的请求
// RequestRecovery 可以恢复的请求
func RequestRecovery(appConfig config.AppConfig,
connectConfig *env.ConnectConfig,
callBack *CallBack) (interface{}, error) {
Expand Down
18 changes: 13 additions & 5 deletions protocol/http/request_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ var servicesResponseStr = `[{

var normalBackupConfigCount = 0

//Normal response
//First request will hold 5s and response http.StatusNotModified
//Second request will hold 5s and response http.StatusNotModified
//Second request will response [{"namespaceName":"application","notificationId":3}]
// Normal response
// First request will hold 5s and response http.StatusNotModified
// Second request will hold 5s and response http.StatusNotModified
// Second request will response [{"namespaceName":"application","notificationId":3}]
func runNormalBackupConfigResponse() *httptest.Server {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
normalBackupConfigCount++
Expand Down Expand Up @@ -84,7 +84,7 @@ func runNormalBackupConfigResponseWithHTTPS() *httptest.Server {
return ts
}

//wait long time then response
// wait long time then response
func runLongTimeResponse() *httptest.Server {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(10 * time.Second)
Expand All @@ -94,3 +94,11 @@ func runLongTimeResponse() *httptest.Server {

return ts
}

func runStatusCodeResponse(status int) *httptest.Server {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(status)
}))

return ts
}
40 changes: 39 additions & 1 deletion protocol/http/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package http

import (
"fmt"
"net/http"
"net/url"
"testing"
"time"
Expand Down Expand Up @@ -133,6 +134,43 @@ func TestCustomTimeout(t *testing.T) {
Assert(t, o, NilVal())
}

func TestFailFastStatusCode(t *testing.T) {
time.Sleep(1 * time.Second)

tests := []struct {
name string
status int
}{
{name: "400", status: http.StatusBadRequest},
{name: "401", status: http.StatusUnauthorized},
{name: "404", status: http.StatusNotFound},
{name: "405", status: http.StatusMethodNotAllowed},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
testFailFastStatusCode(t, tt.status)
})
}
}

func testFailFastStatusCode(t *testing.T, status int) {
server := runStatusCodeResponse(status)
appConfig := getTestAppConfig()
appConfig.IP = server.URL

startTime := time.Now().Unix()
_, err := RequestRecovery(*appConfig, &env.ConnectConfig{
URI: getConfigURLSuffix(appConfig, appConfig.NamespaceName),
IsRetry: true,
}, &CallBack{
SuccessCallBack: nil,
})
duration := time.Now().Unix() - startTime

Assert(t, err, NotNilVal())
Assert(t, int64(0), Equal(duration))
}

func mockIPList(t *testing.T, appConfigFunc func() config.AppConfig) {
time.Sleep(1 * time.Second)

Expand All @@ -159,7 +197,7 @@ func getConfigURLSuffix(config *config.AppConfig, namespaceName string) string {
utils.GetInternal())
}

//SyncServerIPListSuccessCallBack 同步服务器列表成功后的回调
// SyncServerIPListSuccessCallBack 同步服务器列表成功后的回调
func SyncServerIPListSuccessCallBack(responseBody []byte, callback CallBack) (o interface{}, err error) {
log.Debugf("get all server info: %s", string(responseBody))

Expand Down

0 comments on commit f147bf5

Please sign in to comment.