Skip to content

Instantly share code, notes, and snippets.

@jasdel
Last active August 29, 2015 14:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasdel/e0346d861756e14399dc to your computer and use it in GitHub Desktop.
Save jasdel/e0346d861756e14399dc to your computer and use it in GitHub Desktop.
Example of net/http Client not retrying or handling the case where the server closes the pooled connection before it knows and attempts to write the the pool conneciton.
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"time"
)
// Example of net/http client not attempting to reconnect to HTTP/1.1 reused
// connection if the server closed the connection due to read timeout.
//
// Seems to be a timing issue before net/http Client realizes the connection is
// closed, and a new request being made.
func main() {
port := 8080
// When server read timeout matches or within unknown range of request delay
// the net/http Client will attempt to write to the connection but fail
// because the server just then closed the connection. net/http Client will
// not realize the error and retry the request.
serverReadTimeout := 6 * time.Second
requestDelay := 6 * time.Second
go server(port, serverReadTimeout)
time.Sleep(2 * time.Second)
for {
client(port)
time.Sleep(requestDelay)
}
}
func server(port int, readTimeout time.Duration) {
listener, err := net.ListenTCP("tcp", &net.TCPAddr{Port: port})
if err != nil {
panic(err)
}
s := &http.Server{
Handler: serve,
ReadTimeout: readTimeout,
}
if err := s.Serve(listener); err != nil {
panic(err)
}
}
var serve http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
if _, err := w.Write([]byte("hello there!")); err != nil {
fmt.Println("server failed write:", err)
}
}
func client(port int) {
body := bytes.NewReader([]byte("hello everybody"))
req, err := http.NewRequest("POST", fmt.Sprintf("http://localhost:%d", port), body)
if err != nil {
panic(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
if e, ok := err.(*url.Error); ok {
if e.Err == io.EOF {
// Do something with the failed request
fmt.Println("Received io.EOF from request", e)
return
}
}
fmt.Println("client request err:", err)
return
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("client read err:", err)
return
}
fmt.Println("client response:", resp.StatusCode, string(b))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment