Support retry with multiple RPC endpoints
Some checks failed
CI / test (macos-11) (push) Has been cancelled
CI / test (ubuntu-20.04) (push) Has been cancelled

This commit is contained in:
JaydenLink
2025-06-03 16:45:01 +08:00
parent 9374f72fca
commit 1ddc7e0698
2 changed files with 46 additions and 26 deletions

View File

@@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"fmt"
"github.com/block-vision/sui-go-sdk/models" "github.com/block-vision/sui-go-sdk/models"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@@ -12,12 +13,17 @@ import (
"golang.org/x/time/rate" "golang.org/x/time/rate"
) )
const defaultTimeout = time.Second * 5 const (
defaultTimeout = time.Second * 5
defaultRetryCount = 3
)
type HttpConn struct { type HttpConn struct {
c *http.Client c *http.Client
rl *rate.Limiter rl *rate.Limiter
rpcUrl string rpcUrl string
backupRPCURL []string
retryCount int
timeout time.Duration timeout time.Duration
} }
@@ -26,11 +32,13 @@ func newDefaultRateLimiter() *rate.Limiter {
return rateLimiter return rateLimiter
} }
func NewHttpConn(rpcUrl string) *HttpConn { func NewHttpConn(rpcUrl string, backupRPCs []string) *HttpConn {
return &HttpConn{ return &HttpConn{
c: &http.Client{}, c: &http.Client{},
rpcUrl: rpcUrl, rpcUrl: rpcUrl,
backupRPCURL: backupRPCs,
timeout: defaultTimeout, timeout: defaultTimeout,
retryCount: defaultRetryCount,
} }
} }
@@ -54,21 +62,33 @@ func (h *HttpConn) Request(ctx context.Context, op Operation) ([]byte, error) {
return []byte{}, err return []byte{}, err
} }
request, err := http.NewRequest("POST", h.rpcUrl, bytes.NewBuffer(reqBytes)) // 尝试所有可用的 RPC URL
rpcURLs := append([]string{h.rpcUrl}, h.backupRPCURL...)
var lastErr error
for _, rpc := range rpcURLs {
request, err := http.NewRequest("POST", rpc, bytes.NewBuffer(reqBytes))
if err != nil { if err != nil {
return []byte{}, err lastErr = fmt.Errorf("new request %s err: %v rpc: %s", op.Method, err, rpc)
continue
} }
request = request.WithContext(ctx) request = request.WithContext(ctx)
request.Header.Add("Content-Type", "application/json") request.Header.Add("Content-Type", "application/json")
rsp, err := h.c.Do(request.WithContext(ctx)) rsp, err := h.c.Do(request.WithContext(ctx))
if err != nil { if err != nil {
return []byte{}, err lastErr = fmt.Errorf("request %s err: %v rpc: %s", op.Method, err, rpc)
continue
} }
defer rsp.Body.Close() defer rsp.Body.Close()
bodyBytes, err := ioutil.ReadAll(rsp.Body) bodyBytes, err := ioutil.ReadAll(rsp.Body)
if err != nil { if err != nil {
return []byte{}, err lastErr = err
continue
} }
return bodyBytes, nil return bodyBytes, nil
} }
return []byte{}, lastErr
}

View File

@@ -35,8 +35,8 @@ type Client struct {
} }
// NewSuiClient instantiates the Sui client to call the methods of each module. // NewSuiClient instantiates the Sui client to call the methods of each module.
func NewSuiClient(rpcUrl string) ISuiAPI { func NewSuiClient(mainRPC string, backupRPCs ...string) ISuiAPI {
conn := httpconn.NewHttpConn(rpcUrl) conn := httpconn.NewHttpConn(mainRPC, backupRPCs)
return newClient(conn) return newClient(conn)
} }