fasthttp
fasthttp copied to clipboard
Is it possible to group pending response from HTTP Client and process new HTTP Request?
Hi, Using HTTP Client, is it possible to group pending response from HTTP Client and process new HTTP Request?
There are cases when the client is too slow and it slow the entire HTTP client Processing. So wondering if this library provides any approaches?
I'm not sure what you mean? This is a HTTP1 only library. HTTP1 doesn't support out of order responses, only HTTP2 does.
If a client does another request on another connection those will automatically be handled in parallel.
Actually, I was wondering if I could send as much payload to one URL by opening one TCP Connection to that URL and TCP Connection would process each payload one after another.
Here this piece of code sends Request by creating multiple TCP Connection
func main() {
start := time.Now()
// var wg sync.WaitGroup
sliceLength := 500
for i := 0; i < sliceLength; i++ {
go func(i int) {
Request("http://116.203.188.34/send")
// context.Send(pid, Hello{Who: })
}(i)
}
// wg.Wait()
elapsed := time.Since(start)
log.Printf("Binomial took %s", elapsed)
console.ReadLine()
}
var HttpClient = &fasthttp.Client{
NoDefaultUserAgentHeader: true, // Don't send: User-Agent: fasthttp
MaxConnsPerHost: 10000,
ReadBufferSize: 4096, // Make sure to set this big enough that your whole request can be read at once.
WriteBufferSize: 4096, // Same but for your response.
ReadTimeout: 8 * time.Second,
WriteTimeout: 8 * time.Second,
MaxIdleConnDuration: 30 * time.Second,
DisableHeaderNamesNormalizing: true, // If you set the case on your headers correctly you can enable this.
}
func Request(url string) {
destUrl := []byte(url)
req := fasthttp.AcquireRequest()
res := fasthttp.AcquireResponse()
req.SetRequestURIBytes(destUrl)
if err := HttpClient.Do(req, res); err != nil {
println(err.Error())
}
fasthttp.ReleaseRequest(req)
if res.StatusCode() == 200 {
// fmt.Println(BytesToString(res.Body()))
fasthttp.ReleaseResponse(res)
}
}
Is it possible to append as many payloads as possible to one TCP connection and TCP connection would process Payload in FIFO manner
That is called HTTP Pipelining and you can use fasthttp.PipelineClient for that. But not all servers might support it. The fasthttp Server does.
Great! Thanks @erikdubbelboer Is there any example for that function
@erikdubbelboer I tried following code but getting Timeout error even I set to 10 min
package bootstrap
import (
"github.com/valyala/fasthttp" //nolint:goimports
"net/url"
"reflect"
"sync"
"time"
"unsafe" //nolint:goimports
)
var HTTPClients = make(map[string]*fasthttp.PipelineClient) //nolint:gochecknoglobals
func CreatePipelineClient(url string) *fasthttp.PipelineClient {
return &fasthttp.PipelineClient { //nolint:gofmt
Addr: url,
MaxConns: 10000,
MaxPendingRequests: 1000,
MaxBatchDelay: 0,
Dial: nil,
DialDualStack: false,
IsTLS: false,
TLSConfig: nil,
MaxIdleConnDuration: 30 * time.Minute,
ReadBufferSize: 4096,
WriteBufferSize: 4096,
ReadTimeout: 10 * time.Minute,
WriteTimeout: 10 * time.Minute,
Logger: nil,
}
}
func Request(uri string) {
var syncMap sync.Map
u, _ := url.Parse(uri)
if _, ok := HTTPClients[u.Host]; !ok {
syncMap.Store(u.Host, CreatePipelineClient(u.Host))
HTTPClients[u.Host] = CreatePipelineClient(u.Host)
}
client := HTTPClients[u.Host]
destUrl := []byte(uri)
req := fasthttp.AcquireRequest()
res := fasthttp.AcquireResponse()
req.SetRequestURIBytes(destUrl)
if err := client.Do(req, res); err != nil {
println(err.Error())
}
fasthttp.ReleaseRequest(req)
if res.StatusCode() == 200 {
// fmt.Println(BytesToString(res.Body()))
fasthttp.ReleaseResponse(res)
}
}
func BytesToString(b []byte) string {
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
sh := reflect.StringHeader{Data: bh.Data, Len: bh.Len}
return *(*string)(unsafe.Pointer(&sh)) //nolint:wsl
}
Error:
2020/06/16 00:03:48 error in PipelineClient("116.203.188.34"): timeout
2020/06/16 00:03:48 error in PipelineClient("116.203.188.34"): timeout
AND
2020/06/16 00:04:33 error in PipelineClient("116.203.188.34"): dialing to the given TCP address timed out
2020/06/16 00:04:33 error in PipelineClient("116.203.188.34"): dialing to the given TCP address timed out
Can you please suggest me on what mistake have I done in above code?
These both works for me with your code:
func main() {
Request("http://34.188.203.116/test")
Request("http://static.34.188.203.116.clients.your-server.de/test")
}
How are you calling Request?
I was using following
func main() {
start := time.Now()
// var wg sync.WaitGroup
sliceLength := 5000
for i := 0; i < sliceLength; i++ {
go func(i int) {
bootstrap.Request("http://116.203.188.34/send")
}(i)
}
// wg.Wait()
elapsed := time.Since(start)
log.Printf("Binomial took %s", elapsed)
console.ReadLine()
}
When there's high number of concurrent request, I get above error.
pipeline connection has been stopped
pipeline connection has been stopped
2020/06/16 18:14:23 error in PipelineClient("116.203.188.34"): EOF
pipeline connection has been stopped
Looks like the server doesn't want to handle that many connections at the same time. Not much fasthttp can do about that.
I think this is server related, @itsursujit did you managed to solve this issue? If so, please let us know so we can close this 👍
@Fenny I didn't manage to solve this issue. I didn't have a chance to look into this as I was then using net/http