Support retry with multiple RPC endpoints
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/block-vision/sui-go-sdk/models"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@@ -12,12 +13,17 @@ import (
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
const defaultTimeout = time.Second * 5
|
||||
const (
|
||||
defaultTimeout = time.Second * 5
|
||||
defaultRetryCount = 3
|
||||
)
|
||||
|
||||
type HttpConn struct {
|
||||
c *http.Client
|
||||
rl *rate.Limiter
|
||||
rpcUrl string
|
||||
backupRPCURL []string
|
||||
retryCount int
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
@@ -26,11 +32,13 @@ func newDefaultRateLimiter() *rate.Limiter {
|
||||
return rateLimiter
|
||||
}
|
||||
|
||||
func NewHttpConn(rpcUrl string) *HttpConn {
|
||||
func NewHttpConn(rpcUrl string, backupRPCs []string) *HttpConn {
|
||||
return &HttpConn{
|
||||
c: &http.Client{},
|
||||
rpcUrl: rpcUrl,
|
||||
backupRPCURL: backupRPCs,
|
||||
timeout: defaultTimeout,
|
||||
retryCount: defaultRetryCount,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,21 +62,33 @@ func (h *HttpConn) Request(ctx context.Context, op Operation) ([]byte, error) {
|
||||
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 {
|
||||
return []byte{}, err
|
||||
lastErr = fmt.Errorf("new request %s err: %v rpc: %s", op.Method, err, rpc)
|
||||
continue
|
||||
}
|
||||
request = request.WithContext(ctx)
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
|
||||
rsp, err := h.c.Do(request.WithContext(ctx))
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
lastErr = fmt.Errorf("request %s err: %v rpc: %s", op.Method, err, rpc)
|
||||
continue
|
||||
}
|
||||
defer rsp.Body.Close()
|
||||
|
||||
bodyBytes, err := ioutil.ReadAll(rsp.Body)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
return bodyBytes, nil
|
||||
}
|
||||
|
||||
return []byte{}, lastErr
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ type Client struct {
|
||||
}
|
||||
|
||||
// NewSuiClient instantiates the Sui client to call the methods of each module.
|
||||
func NewSuiClient(rpcUrl string) ISuiAPI {
|
||||
conn := httpconn.NewHttpConn(rpcUrl)
|
||||
func NewSuiClient(mainRPC string, backupRPCs ...string) ISuiAPI {
|
||||
conn := httpconn.NewHttpConn(mainRPC, backupRPCs)
|
||||
return newClient(conn)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user