var (
httpClient *http.Client
)
const (
MaxIdleConnections int = 20
RequestTimeout int = 5
)
// init HTTPClient
func init() {
client := &http.Client{
Transport: &http.Transport{
MaxIdleConnsPerHost: MaxIdleConnections,
},
Timeout: time.Duration(RequestTimeout) * time.Second,
}
return client
}
func makeRequest() {
var endPoint string = "https://localhost:8080/doSomething"
req, err := http.NewRequest("GET", ....)
response, err := httpClient.Do(req)
if err != nil && response == nil {
log.Fatalf("Error sending request to API endpoint. %+v", err)
} else {
// Close the connection to reuse it
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatalf("Couldn't parse response body. %+v", err)
}
log.Println("Response Body:", string(body))
}
}
I have the following code in Go. Go uses http-keep-alive connection. Thus, from my understanding, httpClient.Do(req)
will not create a new connection, since golang uses default persistent connections.
-
From my understanding HTTP persistent connection makes one request at a time, ie the second request can only be made after first response. However if multiple threads call
makeRequest()
what will happen ? WillhttpClient.Do(req)
send another request even before previous one got a response ? -
I assume server times-out any keep-alive connection made by client. If server were to timeout, then the next time
httpClient.Do(req)
is called, would it establish a new connection ?
2
Answers
an
http.Client
has aTransport
to which it delegates a lot of the low-level details of making a request. You can change pretty much anything by giving your client a custom Transport. The rest of this answer will largely assume that you’re usinghttp.DefaultClient
or at least a client withhttp.DefaultTransport
.When making a new request, if an idle connection to the appropriate server is available, the transport will use it.
If no idle connection is available (because there never was one, or because other goroutines are using them all, or because the server closed the connection, or there was some other error) then the transport will consider making a new connection, limited by
MaxConnsPerHost
(default: no limit). IfMaxConnsPerHost
would be exceeded, then the request will block until an existing request completes and a connection becomes available. Otherwise, a new connection will be made for this request.On completion of a request, the client will cache the connection for later use (limited by
MaxIdleConns
andMaxIdleConnsPerHost
;DefaultTransport
has a limit of 100 idle connections globally, and no limit per-host).Idle connections will be closed after
IdleConnTimeout
if they aren’t used to make a request; forDefaultTransport
the limit is 90 seconds.All of which means that by default, Go will make enough connections to satisfy parallelism (up to certain limits which you can adjust) but it will also reuse keep-alive connections as much as possible by maintaining a pool of idle connections for some length of time.
It will not affect the http keep-alive connection, base on your code, you are using global httpClient, this will not create a new connection if called in multiple thread as you expected, Also it read the
response.Body
before it closed. If the providedresponse.Body
is anio.Closer
, it will closed after the request.