Last active
August 29, 2015 14:20
-
-
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.
This file contains 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 | |
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