aboutsummaryrefslogtreecommitdiff
path: root/client_timing_wait_test.go
diff options
context:
space:
mode:
authorGravatar Daniel Qian <chanjarster@gmail.com> 2020-04-03 23:12:50 +0800
committerGravatar GitHub <noreply@github.com> 2020-04-03 17:12:50 +0200
commit70b1d3bce783c9ed0f6b7e6e8700b091bfdf95f0 (patch)
treeb3b6a3d40853a8d8b23f83f4953e8f50222a007f /client_timing_wait_test.go
parentDon't retry requests with a BodyStream (diff)
downloadfasthttp-70b1d3bce783c9ed0f6b7e6e8700b091bfdf95f0.tar.gz
fasthttp-70b1d3bce783c9ed0f6b7e6e8700b091bfdf95f0.tar.bz2
fasthttp-70b1d3bce783c9ed0f6b7e6e8700b091bfdf95f0.zip
feat: make client to wait when no free connections (#764)
* feat: make client to wait when no free connections * feat: make client to wait when no free connections use AcquireTimer to do timeout instead of using context * feat: make client to wait when no free connections Add BenchmarkClientGetEndToEndWaitConn* to test heap allocation in waiting for free connection situation * feat: make client to wait when no free connections Add BenchmarkHTTPClientGetEndToEndWaitConn* to test heap allocation in waiting for free connection situation * feat: make client to wait when no free connections fix bug in BenchmarkHTTPClientGetEndToEndWaitConn* * feat: make client to wait when no free connections fix bug in TestHostClientMaxConnWaitTimeoutSuccess make it wait longer to avoid ErrNoFreeConns on travis-ci * feat: make client to wait when no free connections fix do not compile benchmark(NetHTTP?)ClientGetEndToEndWaitConn if go version < 1.11.x * feat: make client to wait when no free connections fix the bug that if deadline is earlier than MaxConnWaitTimeout, still wait MaxConnWaitTimeout which later than deadline. * feat: make client to wait when no free connections fix race condition in TestHostClientMaxConnWaitTimeoutError * feat: make client to wait when no free connections fix bug in TestHostClientMaxConnWaitTimeoutWithEarlierDeadline
Diffstat (limited to 'client_timing_wait_test.go')
-rw-r--r--client_timing_wait_test.go166
1 files changed, 166 insertions, 0 deletions
diff --git a/client_timing_wait_test.go b/client_timing_wait_test.go
new file mode 100644
index 0000000..1d1f767
--- /dev/null
+++ b/client_timing_wait_test.go
@@ -0,0 +1,166 @@
+// +build go1.11
+
+package fasthttp
+
+import (
+ "io/ioutil"
+ "net"
+ "net/http"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/valyala/fasthttp/fasthttputil"
+)
+
+func newFasthttpSleepEchoHandler(sleep time.Duration) RequestHandler {
+ return func(ctx *RequestCtx) {
+ time.Sleep(sleep)
+ ctx.Success("text/plain", ctx.RequestURI())
+ }
+}
+
+func BenchmarkClientGetEndToEndWaitConn1Inmemory(b *testing.B) {
+ benchmarkClientGetEndToEndWaitConnInmemory(b, 1)
+}
+
+func BenchmarkClientGetEndToEndWaitConn10Inmemory(b *testing.B) {
+ benchmarkClientGetEndToEndWaitConnInmemory(b, 10)
+}
+
+func BenchmarkClientGetEndToEndWaitConn100Inmemory(b *testing.B) {
+ benchmarkClientGetEndToEndWaitConnInmemory(b, 100)
+}
+
+func BenchmarkClientGetEndToEndWaitConn1000Inmemory(b *testing.B) {
+ benchmarkClientGetEndToEndWaitConnInmemory(b, 1000)
+}
+
+func benchmarkClientGetEndToEndWaitConnInmemory(b *testing.B, parallelism int) {
+ ln := fasthttputil.NewInmemoryListener()
+
+ ch := make(chan struct{})
+ sleepDuration := 50 * time.Millisecond
+ go func() {
+
+ if err := Serve(ln, newFasthttpSleepEchoHandler(sleepDuration)); err != nil {
+ b.Errorf("error when serving requests: %s", err)
+ }
+ close(ch)
+ }()
+
+ c := &Client{
+ MaxConnsPerHost: 1,
+ Dial: func(addr string) (net.Conn, error) { return ln.Dial() },
+ MaxConnWaitTimeout: 5 * time.Second,
+ }
+
+ requestURI := "/foo/bar?baz=123&sleep=10ms"
+ url := "http://unused.host" + requestURI
+ b.SetParallelism(parallelism)
+ b.RunParallel(func(pb *testing.PB) {
+ var buf []byte
+ for pb.Next() {
+ statusCode, body, err := c.Get(buf, url)
+ if err != nil {
+ if err != ErrNoFreeConns {
+ b.Fatalf("unexpected error: %s", err)
+ }
+ } else {
+ if statusCode != StatusOK {
+ b.Fatalf("unexpected status code: %d. Expecting %d", statusCode, StatusOK)
+ }
+ if string(body) != requestURI {
+ b.Fatalf("unexpected response %q. Expecting %q", body, requestURI)
+ }
+ }
+ buf = body
+ }
+ })
+
+ ln.Close()
+ select {
+ case <-ch:
+ case <-time.After(time.Second):
+ b.Fatalf("server wasn't stopped")
+ }
+}
+
+func newNethttpSleepEchoHandler(sleep time.Duration) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ time.Sleep(sleep)
+ w.Header().Set(HeaderContentType, "text/plain")
+ w.Write([]byte(r.RequestURI)) //nolint:errcheck
+ }
+}
+
+func BenchmarkNetHTTPClientGetEndToEndWaitConn1Inmemory(b *testing.B) {
+ benchmarkNetHTTPClientGetEndToEndWaitConnInmemory(b, 1)
+}
+
+func BenchmarkNetHTTPClientGetEndToEndWaitConn10Inmemory(b *testing.B) {
+ benchmarkNetHTTPClientGetEndToEndWaitConnInmemory(b, 10)
+}
+
+func BenchmarkNetHTTPClientGetEndToEndWaitConn100Inmemory(b *testing.B) {
+ benchmarkNetHTTPClientGetEndToEndWaitConnInmemory(b, 100)
+}
+
+func BenchmarkNetHTTPClientGetEndToEndWaitConn1000Inmemory(b *testing.B) {
+ benchmarkNetHTTPClientGetEndToEndWaitConnInmemory(b, 1000)
+}
+
+func benchmarkNetHTTPClientGetEndToEndWaitConnInmemory(b *testing.B, parallelism int) {
+ ln := fasthttputil.NewInmemoryListener()
+
+ ch := make(chan struct{})
+ sleep := 50 * time.Millisecond
+ go func() {
+ if err := http.Serve(ln, newNethttpSleepEchoHandler(sleep)); err != nil && !strings.Contains(
+ err.Error(), "use of closed network connection") {
+ b.Errorf("error when serving requests: %s", err)
+ }
+ close(ch)
+ }()
+
+ c := &http.Client{
+ Transport: &http.Transport{
+ Dial: func(_, _ string) (net.Conn, error) { return ln.Dial() },
+ MaxConnsPerHost: 1,
+ },
+ Timeout: 5 * time.Second,
+ }
+
+ requestURI := "/foo/bar?baz=123"
+ url := "http://unused.host" + requestURI
+ b.SetParallelism(parallelism)
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ resp, err := c.Get(url)
+ if err != nil {
+ if netErr, ok := err.(net.Error); !ok || !netErr.Timeout() {
+ b.Fatalf("unexpected error: %s", err)
+ }
+ } else {
+ if resp.StatusCode != http.StatusOK {
+ b.Fatalf("unexpected status code: %d. Expecting %d", resp.StatusCode, http.StatusOK)
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ if err != nil {
+ b.Fatalf("unexpected error when reading response body: %s", err)
+ }
+ if string(body) != requestURI {
+ b.Fatalf("unexpected response %q. Expecting %q", body, requestURI)
+ }
+ }
+ }
+ })
+
+ ln.Close()
+ select {
+ case <-ch:
+ case <-time.After(time.Second):
+ b.Fatalf("server wasn't stopped")
+ }
+}