Просмотр исходного кода

Merge pull request #260 from aliyun/dev_4.15

fix timeout error
wenzuochao 6 лет назад
Родитель
Сommit
f4d14ceb6e
4 измененных файлов с 30 добавлено и 25 удалено
  1. 1 1
      docs/5-Timeout-CN.md
  2. 1 1
      docs/5-Timeout-EN.md
  3. 2 3
      integration/core_test.go
  4. 26 20
      sdk/client.go

+ 1 - 1
docs/5-Timeout-CN.md

@@ -4,7 +4,7 @@
 # 超时
 
 ## 描述
-如果你想限制请求花费的时间,你可以通过请求或者客户端设置 `ReadTimeout` 和 `ConnectTimeout`。
+如果你想限制请求花费的时间,你可以通过请求或者客户端设置 `ConnectTimeout` 和 `ReadTimeout`。
 
 ## 默认值
 - `defaultConnectTimeout`: 5 秒

+ 1 - 1
docs/5-Timeout-EN.md

@@ -4,7 +4,7 @@
 # Timeout
 
 ## Description
-When you want to limit the time of request costing, you can set `ReadTimeout` and `ConnectTimeout` by request or client:
+When you want to limit the time of request costing, you can set `ConnectTimeout` and `ReadTimeout` by request or client:
 
 ## Default
 - `defaultConnectTimeout`: 5 * time.Second

+ 2 - 3
integration/core_test.go

@@ -196,7 +196,7 @@ func Test_DescribeClusterDetailWithCommonRequestWithTimeout(t *testing.T) {
 	request.PathPattern = "/clusters/[ClusterId]"
 	request.QueryParams["RegionId"] = os.Getenv("REGION_ID")
 	request.ReadTimeout = 1 * time.Millisecond
-	request.ConnectTimeout = 1 * time.Millisecond
+	request.ConnectTimeout = 1 * time.Nanosecond
 	request.TransToAcsRequest()
 	_, err = client.ProcessCommonRequest(request)
 	assert.NotNil(t, err)
@@ -315,7 +315,6 @@ func Test_HTTPProxy(t *testing.T) {
 	os.Setenv("HTTP_PROXY", originEnv)
 }
 
-
 func Test_DdoscooWithServiceCode(t *testing.T) {
 	client, err := sdk.NewClientWithAccessKey(os.Getenv("REGION_ID"), os.Getenv("ACCESS_KEY_ID"), os.Getenv("ACCESS_KEY_SECRET"))
 	assert.Nil(t, err)
@@ -328,4 +327,4 @@ func Test_DdoscooWithServiceCode(t *testing.T) {
 	_, err = client.ProcessCommonRequest(request)
 	assert.NotNil(t, err)
 	assert.Contains(t, err.Error(), "InstanceIds is mandatory for this action.")
-}
+}

+ 26 - 20
sdk/client.go

@@ -403,6 +403,8 @@ func (client *Client) getTimeout(request requests.AcsRequest) (time.Duration, ti
 		readTimeout = reqReadTimeout
 	} else if client.readTimeout != 0*time.Millisecond {
 		readTimeout = client.readTimeout
+	} else if client.httpClient.Timeout != 0 && client.httpClient.Timeout != 10000000000 {
+		readTimeout = client.httpClient.Timeout
 	}
 
 	if reqConnectTimeout != 0*time.Millisecond {
@@ -413,12 +415,10 @@ func (client *Client) getTimeout(request requests.AcsRequest) (time.Duration, ti
 	return readTimeout, connectTimeout
 }
 
-func Timeout(connectTimeout, readTimeout time.Duration) func(cxt context.Context, net, addr string) (c net.Conn, err error) {
+func Timeout(connectTimeout time.Duration) func(cxt context.Context, net, addr string) (c net.Conn, err error) {
 	return func(ctx context.Context, network, address string) (net.Conn, error) {
 		return (&net.Dialer{
 			Timeout:   connectTimeout,
-			Deadline:  time.Now().Add(readTimeout),
-			KeepAlive: 0 * time.Second,
 			DualStack: true,
 		}).DialContext(ctx, network, address)
 	}
@@ -426,12 +426,13 @@ func Timeout(connectTimeout, readTimeout time.Duration) func(cxt context.Context
 
 func (client *Client) setTimeout(request requests.AcsRequest) {
 	readTimeout, connectTimeout := client.getTimeout(request)
+	client.httpClient.Timeout = readTimeout
 	if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil {
-		trans.DialContext = Timeout(connectTimeout, readTimeout)
+		trans.DialContext = Timeout(connectTimeout)
 		client.httpClient.Transport = trans
 	} else {
 		client.httpClient.Transport = &http.Transport{
-			DialContext: Timeout(connectTimeout, readTimeout),
+			DialContext: Timeout(connectTimeout),
 		}
 	}
 }
@@ -496,22 +497,14 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
 			client.printLog(fieldMap, err)
 			initLogMsg(fieldMap)
 		}
+		putMsgToMap(fieldMap, httpRequest)
 		debug("> %s %s %s", httpRequest.Method, httpRequest.URL.RequestURI(), httpRequest.Proto)
 		debug("> Host: %s", httpRequest.Host)
-		fieldMap["{host}"] = httpRequest.Host
-		fieldMap["{method}"] = httpRequest.Method
-		fieldMap["{uri}"] = httpRequest.URL.RequestURI()
-		fieldMap["{pid}"] = strconv.Itoa(os.Getpid())
-		fieldMap["{version}"] = strings.Split(httpRequest.Proto, "/")[1]
-		hostname, _ := os.Hostname()
-		fieldMap["{hostname}"] = hostname
-		fieldMap["{req_headers}"] = TransToString(httpRequest.Header)
-		fieldMap["{target}"] = httpRequest.URL.Path + httpRequest.URL.RawQuery
 		for key, value := range httpRequest.Header {
 			debug("> %s: %v", key, strings.Join(value, ""))
 		}
 		debug(">")
-		debug("> Retry Times: %d.", retryTimes)
+		debug(" Retry Times: %d.", retryTimes)
 
 		startTime := time.Now()
 		fieldMap["{start_time}"] = startTime.Format("2006-01-02 15:04:05")
@@ -528,16 +521,17 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
 		debug("<")
 		// receive error
 		if err != nil {
-			debug("< Error %s.", err.Error())
+			debug(" Error: %s.", err.Error())
 			if !client.config.AutoRetry {
 				return
 			} else if retryTimes >= client.config.MaxRetryTime {
 				// timeout but reached the max retry times, return
-				var timeoutErrorMsg string
-				if strings.Contains(err.Error(), "read tcp") {
-					timeoutErrorMsg = fmt.Sprintf(errors.TimeoutErrorMessage, strconv.Itoa(retryTimes+1), strconv.Itoa(retryTimes+1)) + " Read timeout. Please set a valid ReadTimeout."
+				times := strconv.Itoa(retryTimes + 1)
+				timeoutErrorMsg := fmt.Sprintf(errors.TimeoutErrorMessage, times, times)
+				if strings.Contains(err.Error(), "Client.Timeout") {
+					timeoutErrorMsg += " Read timeout. Please set a valid ReadTimeout."
 				} else {
-					timeoutErrorMsg = fmt.Sprintf(errors.TimeoutErrorMessage, strconv.Itoa(retryTimes+1), strconv.Itoa(retryTimes+1)) + " Connect timeout. Please set a valid ConnectTimeout."
+					timeoutErrorMsg += " Connect timeout. Please set a valid ConnectTimeout."
 				}
 				err = errors.NewClientError(errors.TimeoutErrorCode, timeoutErrorMsg, err)
 				return
@@ -567,6 +561,18 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
 	return
 }
 
+func putMsgToMap(fieldMap map[string]string, request *http.Request) {
+	fieldMap["{host}"] = request.Host
+	fieldMap["{method}"] = request.Method
+	fieldMap["{uri}"] = request.URL.RequestURI()
+	fieldMap["{pid}"] = strconv.Itoa(os.Getpid())
+	fieldMap["{version}"] = strings.Split(request.Proto, "/")[1]
+	hostname, _ := os.Hostname()
+	fieldMap["{hostname}"] = hostname
+	fieldMap["{req_headers}"] = TransToString(request.Header)
+	fieldMap["{target}"] = request.URL.Path + request.URL.RawQuery
+}
+
 func buildHttpRequest(request requests.AcsRequest, singer auth.Signer, regionId string) (httpRequest *http.Request, err error) {
 	err = auth.Sign(request, singer, regionId)
 	if err != nil {