diff options
author | Daniel Qian <chanjarster@gmail.com> | 2020-04-03 23:12:50 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-03 17:12:50 +0200 |
commit | 70b1d3bce783c9ed0f6b7e6e8700b091bfdf95f0 (patch) | |
tree | b3b6a3d40853a8d8b23f83f4953e8f50222a007f /client_timing_wait_test.go | |
parent | Don't retry requests with a BodyStream (diff) | |
download | fasthttp-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.go | 166 |
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") + } +} |