Open 9iang22 opened 2 years ago
Could repro, looks like the following diff kinda fixes it. Maybe we should add a timeout to the rpc server/rpc client context.
diff --git a/rpc/handler.go b/rpc/handler.go
index f3052e7eb..f921e30ac 100644
--- a/rpc/handler.go
+++ b/rpc/handler.go
@@ -219,7 +219,7 @@ func (h *handler) cancelServerSubscriptions(err error) {
func (h *handler) startCallProc(fn func(*callProc)) {
h.callWG.Add(1)
go func() {
- ctx, cancel := context.WithCancel(h.rootCtx)
+ ctx, cancel := context.WithTimeout(h.rootCtx, time.Second)
defer h.callWG.Done()
defer cancel()
fn(&callProc{ctx: ctx})
*Edit To be clear I'm not proposing this as a fix, it should only show where the issue is
i try to test it but i need to know "goleak" in which branch
i try to test it but i need to know "goleak" in which branch
It's a third party leak checker, include by go.uber.org/goleak
http is also leaking.
func TestHTTPClientGoroutineLeak(t *testing.T) {
defer goleak.VerifyNone(t)
ctx := context.Background()
// connect to local node
client, err := DialContext(ctx, "http://localhost:8545")
if err != nil {
t.Fatal("can't dial", err)
}
defer client.Close()
if err := client.CallContext(ctx, nil, "eth_chainId"); err != nil {
t.Fatal(err)
}
}
// Once run above test, go routine leak detected.
--- FAIL: TestHTTPClientGoroutineLeak (0.45s)
/Users/tak/Documents/angoya/_sandbox/go-ethereum/rpc/client_test.go:70: found unexpected goroutines:
[Goroutine 25 in state IO wait, with internal/poll.runtime_pollWait on top of the stack:
...
Then I noticed that missing to close idling connections
diff --git a/rpc/http.go b/rpc/http.go
index bbabe15ba..4f45d8d46 100644
--- a/rpc/http.go
+++ b/rpc/http.go
@@ -73,6 +73,7 @@ func (hc *httpConn) readBatch() ([]*jsonrpcMessage, bool, error) {
func (hc *httpConn) close() {
hc.closeOnce.Do(func() { close(hc.closeCh) })
+ hc.client.CloseIdleConnections()
}
And missing httpConn.close()
diff --git a/rpc/client.go b/rpc/client.go
index a509cb2e0..e508ed304 100644
--- a/rpc/client.go
+++ b/rpc/client.go
@@ -280,6 +280,7 @@ func (c *Client) SupportedModules() (map[string]string, error) {
// Close closes the client, aborting any in-flight requests.
func (c *Client) Close() {
if c.isHTTP {
+ c.writeConn.(*httpConn).close()
return
}
Those two changes solve go routine leak.
System information
OS & Version: Windows 11 & Ubuntu 18.04 Commit hash : develop
When I run the TestClientCancelWebsocket with goleak, there are some go routine leaks, as mentioned below. Actually I think it blocks at this function.
In
TestClientCancelWebsocket
, thefn
is to test block (test_block
) so I think it may block forever and theh.callWG.Done
will never be called. Although it is caused by a client test, it causes leaks in the server part. I wonder if it is normal for thisfn
call without a timeout.Expected behaviour
Pass
Actual behaviour
Steps to reproduce the behaviour
run TestClientCancelWebsocket with goleak
Backtrace