Skip to content

Instantly share code, notes, and snippets.

@feiskyer
Created February 16, 2025 05:55
Show Gist options
  • Save feiskyer/8191cc90a0cb41aadd384498981101e4 to your computer and use it in GitHub Desktop.
Save feiskyer/8191cc90a0cb41aadd384498981101e4 to your computer and use it in GitHub Desktop.
HTTP timeout test
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