Created
February 16, 2025 05:55
-
-
Save feiskyer/8191cc90a0cb41aadd384498981101e4 to your computer and use it in GitHub Desktop.
HTTP timeout test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
/* | |
* Existing TCP timeout: | |
* 1) Set http.Client.Timeout to 1m: 1m | |
* 2) Set http2.ReadIdleTimeout=30s, http2.PingTimeout=15s, http.Client.Timeout=1m: 45s | |
* 3) Without both: 15m | |
* | |
* New TCP timeout: 30s (per dialer setting) | |
* | |
* Notes: | |
* http2.ReadIdleTimeout - The interval of health check for idle connections. | |
* http2.PingTimeout - The timeout for server to respond to a client ping. | |
* http.Client.Timeout - The timeout includes connection time, any redirects, and reading the response body. | |
*/ | |
import ( | |
"crypto/tls" | |
"fmt" | |
"io" | |
"net" | |
"net/http" | |
"time" | |
"golang.org/x/net/http2" | |
) | |
func doRequest(client *http.Client, url string) { | |
startTime := time.Now() | |
req, err := http.NewRequest("GET", url, nil) | |
if err != nil { | |
fmt.Printf("HTTP NewRequest failed with duration: %v, error: %v\n", time.Since(startTime), err) | |
return | |
} | |
rsp, err := client.Do(req) | |
if err != nil { | |
fmt.Printf("HTTP Client Do request failed with duration: %v, error: %v\n", time.Since(startTime), err) | |
return | |
} | |
buf, err := io.ReadAll(rsp.Body) | |
if err != nil { | |
fmt.Printf("HTTP read body failed with duration: %v, error: %v\n", time.Since(startTime), err) | |
return | |
} | |
defer rsp.Body.Close() | |
fmt.Printf("HTTP succeed with duration: %v, resp: %s\n", time.Since(startTime), string(buf)[:15]) | |
} | |
func main() { | |
tr := &http.Transport{ | |
Proxy: http.ProxyFromEnvironment, | |
ForceAttemptHTTP2: false, // default is true | |
MaxIdleConns: 64, // default is 100 | |
MaxIdleConnsPerHost: 64, // default is 2 | |
IdleConnTimeout: 90 * time.Second, // same as default | |
TLSHandshakeTimeout: 10 * time.Second, // same as default | |
ExpectContinueTimeout: 1 * time.Second, // same as default | |
DialContext: (&net.Dialer{ | |
Timeout: 30 * time.Second, | |
KeepAlive: 30 * time.Second, | |
}).DialContext, | |
TLSClientConfig: &tls.Config{ | |
InsecureSkipVerify: true, | |
MinVersion: tls.VersionTLS12, | |
Renegotiation: tls.RenegotiateNever, | |
}, | |
} | |
t2, err := http2.ConfigureTransports(tr) | |
if err != nil { | |
fmt.Printf("time: %v, http2 ConfigureTransports failed: %v\n", time.Now(), err) | |
return | |
} | |
// ReadIdleTimeout configures the interval of health check for idle connections. | |
// If the connection is idle for this duration, the client will send a ping to the server. | |
t2.ReadIdleTimeout = 30 * time.Second | |
// PingTimeout configures the timeout for server to respond to a client ping. | |
// Response exceeding this timeout will cause the connection to be closed. | |
t2.PingTimeout = 15 * time.Second | |
client := &http.Client{ | |
Transport: tr, | |
Timeout: time.Minute, | |
} | |
for i := 0; i < 500; i++ { | |
doRequest(client, "https://www.google.com") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment