From 537c56e401704a2422553b1d0fb5e2e972b61928 Mon Sep 17 00:00:00 2001 From: Kitipong Sirirueangsakul Date: Tue, 19 May 2026 11:45:59 +0700 Subject: [PATCH 1/3] add idletimeout for http --- relayer/chains/evm/client.go | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/relayer/chains/evm/client.go b/relayer/chains/evm/client.go index 630cdea8..fe549c63 100644 --- a/relayer/chains/evm/client.go +++ b/relayer/chains/evm/client.go @@ -4,6 +4,8 @@ import ( "context" "fmt" "math/big" + "net/http" + "strings" "sync" "time" @@ -12,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" "github.com/bandprotocol/falcon/relayer/alert" "github.com/bandprotocol/falcon/relayer/chains" @@ -59,6 +62,32 @@ type client struct { alert alert.Alert } +// idleConnTimeout is intentionally shorter than the typical load-balancer idle +// timeout (e.g. AWS ALB default is 60 s) so Go closes idle keep-alive +// connections before the LB does, preventing "connection reset by peer" errors +// caused by the LB sending a TCP RST on a stale connection that Go's transport +// would otherwise attempt to reuse. +const idleConnTimeout = 30 * time.Second + +// dialEVMEndpoint connects to an EVM-compatible RPC endpoint. +// For HTTP/HTTPS endpoints it injects a custom transport with a short +// IdleConnTimeout to avoid stale-connection resets from load balancers. +// For WebSocket endpoints it falls back to the standard ethclient dialer. +func dialEVMEndpoint(ctx context.Context, endpoint string) (*ethclient.Client, error) { + lower := strings.ToLower(endpoint) + if strings.HasPrefix(lower, "http://") || strings.HasPrefix(lower, "https://") { + transport := &http.Transport{ + IdleConnTimeout: idleConnTimeout, + } + rpcCli, err := rpc.DialOptions(ctx, endpoint, rpc.WithHTTPClient(&http.Client{Transport: transport})) + if err != nil { + return nil, err + } + return ethclient.NewClient(rpcCli), nil + } + return ethclient.DialContext(ctx, endpoint) +} + // NewClient creates a new EVM client from config file and load keys. func NewClient(chainName string, cfg *EVMChainProviderConfig, log logger.Logger, alert alert.Alert) *client { return &client{ @@ -84,7 +113,7 @@ func (c *client) Connect(ctx context.Context) error { wg.Add(1) go func(endpoint string) { defer wg.Done() - client, err := ethclient.Dial(endpoint) + client, err := dialEVMEndpoint(ctx, endpoint) if err != nil { c.Log.Warn( "Failed to connect to EVM chain", From e22fdd029eb7530927ee88ac6dc40d69a2b03a58 Mon Sep 17 00:00:00 2001 From: Kitipong Sirirueangsakul Date: Tue, 19 May 2026 13:29:05 +0700 Subject: [PATCH 2/3] fix from comment --- relayer/chains/evm/client.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/relayer/chains/evm/client.go b/relayer/chains/evm/client.go index fe549c63..22bacf5d 100644 --- a/relayer/chains/evm/client.go +++ b/relayer/chains/evm/client.go @@ -76,9 +76,8 @@ const idleConnTimeout = 30 * time.Second func dialEVMEndpoint(ctx context.Context, endpoint string) (*ethclient.Client, error) { lower := strings.ToLower(endpoint) if strings.HasPrefix(lower, "http://") || strings.HasPrefix(lower, "https://") { - transport := &http.Transport{ - IdleConnTimeout: idleConnTimeout, - } + transport := http.DefaultTransport.(*http.Transport).Clone() + transport.IdleConnTimeout = idleConnTimeout rpcCli, err := rpc.DialOptions(ctx, endpoint, rpc.WithHTTPClient(&http.Client{Transport: transport})) if err != nil { return nil, err @@ -113,6 +112,8 @@ func (c *client) Connect(ctx context.Context) error { wg.Add(1) go func(endpoint string) { defer wg.Done() + ethclient.Dial() + http.DefaultTransport client, err := dialEVMEndpoint(ctx, endpoint) if err != nil { c.Log.Warn( From 92c062789de3040420d263b2b7f8b0264016e365 Mon Sep 17 00:00:00 2001 From: Kitipong Sirirueangsakul Date: Tue, 19 May 2026 13:31:55 +0700 Subject: [PATCH 3/3] fix --- relayer/chains/evm/client.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/relayer/chains/evm/client.go b/relayer/chains/evm/client.go index 22bacf5d..89e85fb7 100644 --- a/relayer/chains/evm/client.go +++ b/relayer/chains/evm/client.go @@ -112,8 +112,6 @@ func (c *client) Connect(ctx context.Context) error { wg.Add(1) go func(endpoint string) { defer wg.Done() - ethclient.Dial() - http.DefaultTransport client, err := dialEVMEndpoint(ctx, endpoint) if err != nil { c.Log.Warn(