Please help me to resolve my problem. I wrote the code what check proxies. In general I run 50 goroutines, each from then get proxy from channel and check if it work and got correct response from my test page. Each goroutine made this relation
request ----> proxy ---> my test page ---> test content from my test page.
function what check this relation is:
// GetAndCheckURL get test page via proxy and check its body.
func GetAndCheckURL(c *http.Client, urlStr string) ([]byte, error) {
resp, err := c.Get(urlStr)
if err != nil {
return nil, fmt.Errorf("request error: %v", err)
}
defer func() {
if err := resp.Body.Close(); err != nil {
packageLogger.Neverf("can't close response body, error: %v", err)
}
}()
if body, err := ioutil.ReadAll(resp.Body); err != nil {
packageLogger.Neverf("Can't read response body, URL '%s', error: %v, response statusCode: %d, status: %s
", urlStr, err, resp.StatusCode, resp.Status)
return nil, err
} else if !bytes.Contains(body, []byte("<!--proxy_test")) {
return nil, errors.New("invalid body")
} else {
return body, nil
}
}
Because each goroutines check different proxies I can't use single http.Transport and http.Client structures. This function GetAndCheckURL
get its http.client with its http.transport (with proxy). This function is running in my workers by this code:
// readProxyWorker worker read proxy from chan.
func readProxyWorker(DB *storm.DB, workerNum int, conf config.CheckTaskConfig, ownIP string, proxyWaitChan <-chan proxy.Proxy, m proxy.CheckMetrics) {
for i := 0; i < workerNum; i++ {
go func() {
var err error
for p := range proxyWaitChan {
// HERE RUN FUNCTION WHAT CHECK PROXIES
}
}()
}
}
But problem is what for socks5 proxies I got leak goroutines.
goroutine 160801 [IO wait, 915 minutes]:
internal/poll.runtime_pollWait(0x7fb2ab337410, 0x72, 0xc4206b96a8)
/usr/local/Cellar/go/1.10.1/libexec/src/runtime/netpoll.go:173 +0x57
internal/poll.(*pollDesc).wait(0xc420c29998, 0x72, 0xffffffffffffff00, 0xb2e180, 0xe34418)
/usr/local/Cellar/go/1.10.1/libexec/src/internal/poll/fd_poll_runtime.go:85 +0x9b
internal/poll.(*pollDesc).waitRead(0xc420c29998, 0xc422915e00, 0x2, 0x13)
/usr/local/Cellar/go/1.10.1/libexec/src/internal/poll/fd_poll_runtime.go:90 +0x3d
internal/poll.(*FD).Read(0xc420c29980, 0xc422915ee0, 0x2, 0x13, 0x0, 0x0, 0x0)
/usr/local/Cellar/go/1.10.1/libexec/src/internal/poll/fd_unix.go:157 +0x17d
net.(*netFD).Read(0xc420c29980, 0xc422915ee0, 0x2, 0x13, 0x0, 0x0, 0xe7c080)
/usr/local/Cellar/go/1.10.1/libexec/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc4214ec1b8, 0xc422915ee0, 0x2, 0x13, 0x0, 0x0, 0x0)
/usr/local/Cellar/go/1.10.1/libexec/src/net/net.go:176 +0x6a
io.ReadAtLeast(0x7fb2ab62d868, 0xc4214ec1b8, 0xc422915ee0, 0x2, 0x13, 0x2, 0xa99f60, 0x0, 0x7fb2ab62d868)
/usr/local/Cellar/go/1.10.1/libexec/src/io/io.go:309 +0x86
io.ReadFull(0x7fb2ab62d868, 0xc4214ec1b8, 0xc422915ee0, 0x2, 0x13, 0x0, 0x0, 0x0)
/usr/local/Cellar/go/1.10.1/libexec/src/io/io.go:327 +0x58
vendor/golang_org/x/net/proxy.(*socks5).connect(0xc4208b6690, 0xb367c0, 0xc4214ec1b8, 0xc42083cd60, 0x11, 0xb367c0, 0xc4214ec1b8)
/usr/local/Cellar/go/1.10.1/libexec/src/vendor/golang_org/x/net/proxy/socks5.go:113 +0x2f5
vendor/golang_org/x/net/proxy.(*socks5).Dial(0xc4208b6690, 0xabaa03, 0x3, 0xc42083cd60, 0x11, 0xc42083ce80, 0x12, 0xb367c0, 0xc4214ec1b8)
/usr/local/Cellar/go/1.10.1/libexec/src/vendor/golang_org/x/net/proxy/socks5.go:75 +0xf3
net/http.(*Transport).dialConn(0xc420e1eff0, 0xb32400, 0xc420020078, 0xc420c29580, 0xc420024780, 0x5, 0xc42083cd60, 0x11, 0xae8d10, 0xc4229ee7b8, ...)
/usr/local/Cellar/go/1.10.1/libexec/src/net/http/transport.go:1176 +0x6f7
net/http.(*Transport).getConn.func4(0xc420e1eff0, 0xb32400, 0xc420020078, 0xc421205a70, 0xc4209fa7e0)
/usr/local/Cellar/go/1.10.1/libexec/src/net/http/transport.go:957 +0x78
created by net/http.(*Transport).getConn
/usr/local/Cellar/go/1.10.1/libexec/src/net/http/transport.go:956 +0x363
goroutine 18553 [chan receive, 27 minutes]:
net/http.(*Transport).getConn.func2.1(0x1a7c8900, 0x19b8ff40, 0x84f7388)
/usr/local/go/src/net/http/transport.go:946 +0x41
created by net/http.(*Transport).getConn.func2
/usr/local/go/src/net/http/transport.go:945 +0x61
And I don't know where is my error. I can resolve this problem only when add deadline for connection (or ReadDeadline and WriteDeadline). But I want to resolve my problem with timeouts. I try many variants of timeouts, but this leak exist. In my http.Transport DisablekeepAlive is true, net.Dialer and http.Client has timeouts.
Help me, please.
I had a similar issue, also had a problem with leak goroutines. First one was related to KeepAlive timeout in Dialer, and another is about TLSHandshakeTimeout. Sometimes my program was getting stuck. The following code should help you to avoid that. Hope it helps you )
&http.Transport{
DialContext: (&net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 5 * time.Second,
DualStack: true,
}).DialContext,
TLSHandshakeTimeout: 2 * time.Second,
ResponseHeaderTimeout: 2 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
DisableKeepAlives: true,
}