From 47f5c13810a639e2249f5cf39524aeeb3972fdf3 Mon Sep 17 00:00:00 2001 From: Dom Del Nano Date: Mon, 25 Sep 2023 22:45:37 -0700 Subject: [PATCH] Add exponential backoff for specific JSON RPC errors Signed-off-by: Dom Del Nano --- client/client.go | 59 ++++++++++++++++++++++++++++++++---------------- go.mod | 1 + go.sum | 2 ++ 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/client/client.go b/client/client.go index a24f6434..76d0fa49 100644 --- a/client/client.go +++ b/client/client.go @@ -15,6 +15,7 @@ import ( "strings" "time" + "github.com/cenkalti/backoff" gorillawebsocket "github.com/gorilla/websocket" "github.com/sourcegraph/jsonrpc2" "github.com/sourcegraph/jsonrpc2/websocket" @@ -227,33 +228,51 @@ func NewClient(config Config) (XOClient, error) { }, nil } -func (c *Client) Call(method string, params, result interface{}, opt ...jsonrpc2.CallOption) error { - err := c.rpc.Call(context.Background(), method, params, result, opt...) - var callRes interface{} - t := reflect.TypeOf(result) - if t == nil || t.Kind() != reflect.Ptr { - callRes = result - } else { - callRes = reflect.ValueOf(result).Elem() +func IsRetryableError(err jsonrpc2.Error) bool { + if err.Code == 11 { + return true } - log.Printf("[TRACE] Made rpc call `%s` with params: %v and received %+v: result with error: %v\n", method, params, callRes, err) - - if err != nil { - rpcErr, ok := err.(*jsonrpc2.Error) + return false +} - if !ok { - return err +func (c *Client) Call(method string, params, result interface{}) error { + operation := func() error { + err := c.rpc.Call(context.Background(), method, params, result) + var callRes interface{} + t := reflect.TypeOf(result) + if t == nil || t.Kind() != reflect.Ptr { + callRes = result + } else { + callRes = reflect.ValueOf(result).Elem() } + log.Printf("[TRACE] Made rpc call `%s` with params: %v and received %+v: result with error: %v\n", method, params, callRes, err) - data := rpcErr.Data + if err != nil { + rpcErr, ok := err.(*jsonrpc2.Error) - if data == nil { - return err - } + if !ok { + return backoff.PermanentError{err} + } - return errors.New(fmt.Sprintf("%s: %s", err, *data)) + if IsRetryableError(rpcErr) { + return err + } + + data := rpcErr.Data + + if data == nil { + return backoff.PermanentError{err} + } + + return backoff.PermanentError{errors.New(fmt.Sprintf("%s: %s", err, *data))} + } + return nil } - return nil + + bo := backoff.NewExponentialBackOff() + // TODO(ddelnano): See if we need to update from the default 15 mins + // bo.MaxElapsedTime = maxElapsedTime + return backoff.Retry(operation, bo) } type RefreshComparison interface { diff --git a/go.mod b/go.mod index c3b927d0..13c02a5c 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/ddelnano/terraform-provider-xenorchestra go 1.16 require ( + github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/ddelnano/terraform-provider-xenorchestra/client v0.0.0-00010101000000-000000000000 github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.3 ) diff --git a/go.sum b/go.sum index 26013d0c..6e9f4692 100644 --- a/go.sum +++ b/go.sum @@ -56,6 +56,8 @@ github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=