@@ -14,6 +14,7 @@ import (
1414 "google.golang.org/grpc/connectivity"
1515 "google.golang.org/grpc/keepalive"
1616 "google.golang.org/grpc/status"
17+ "strings"
1718 msync "sync"
1819 "time"
1920)
@@ -37,21 +38,8 @@ const (
3738 "MaxBackoff": "5s",
3839 "BackoffMultiplier": 2.0,
3940 "RetryableStatusCodes": [
40- "CANCELLED",
4141 "UNKNOWN",
42- "INVALID_ARGUMENT",
43- "NOT_FOUND",
44- "ALREADY_EXISTS",
45- "PERMISSION_DENIED",
46- "RESOURCE_EXHAUSTED",
47- "FAILED_PRECONDITION",
48- "ABORTED",
49- "OUT_OF_RANGE",
50- "UNIMPLEMENTED",
51- "INTERNAL",
52- "UNAVAILABLE",
53- "DATA_LOSS",
54- "UNAUTHENTICATED"
42+ "UNAVAILABLE"
5543 ]
5644 }
5745 }
@@ -61,7 +49,7 @@ const (
6149 nonRetryableStatusCodes = `
6250 [
6351 "PermissionDenied",
64- "Unauthenticated",
52+ "Unauthenticated"
6553 ]
6654 `
6755)
@@ -90,6 +78,7 @@ type Sync struct {
9078 Selector string
9179 URI string
9280 MaxMsgSize int
81+ RetryGracePeriod int
9382
9483 // Runtime state
9584 client FlagSyncServiceClient
@@ -104,7 +93,7 @@ type Sync struct {
10493// Init initializes the gRPC connection and starts background monitoring
10594func (g * Sync ) Init (ctx context.Context ) error {
10695 g .Logger .Info (fmt .Sprintf ("initializing gRPC client for %s" , g .URI ))
107- initNonRetryableStatusCodesSet ()
96+ g . initNonRetryableStatusCodesSet ()
10897
10998 // Initialize channels
11099 g .shutdownComplete = make (chan struct {})
@@ -174,13 +163,16 @@ func (g *Sync) buildDialOptions() ([]grpc.DialOption, error) {
174163}
175164
176165// initNonRetryableStatusCodesSet initializes the set of non-retryable gRPC status codes for quick lookup
177- func initNonRetryableStatusCodesSet () {
166+ func ( g * Sync ) initNonRetryableStatusCodesSet () {
178167 var codes []string
179168 nonRetryableCodes = make (map [string ]struct {})
180- if err := json .Unmarshal ([]byte (nonRetryableStatusCodes ), & codes ); err == nil {
169+ trimmed := strings .TrimSpace (nonRetryableStatusCodes )
170+ if err := json .Unmarshal ([]byte (trimmed ), & codes ); err == nil {
181171 for _ , code := range codes {
182172 nonRetryableCodes [code ] = struct {}{}
183173 }
174+ } else {
175+ g .Logger .Debug ("parsing non-retryable status codes failed, retrying on all errors" )
184176 }
185177}
186178
@@ -245,9 +237,19 @@ func (g *Sync) Sync(ctx context.Context, dataSync chan<- sync.DataSync) error {
245237 if _ , found := nonRetryableCodes [codeStr ]; found {
246238 g .Logger .Error (fmt .Sprintf ("sync cycle failed with non-retryable code: %v" , codeStr ))
247239 return err
240+ errStr := fmt .Sprintf ("sync cycle failed with non-retryable status: %v, " +
241+ "returning provider fatal." , codeStr )
242+ g .Logger .Error (errStr )
243+ return & of.ProviderInitError {
244+ ErrorCode : of .ProviderFatalCode ,
245+ Message : errStr ,
246+ }
248247 }
249248 }
250249
250+ // Backoff before retrying
251+ time .Sleep (time .Duration (g .RetryGracePeriod ))
252+
251253 g .Logger .Warn (fmt .Sprintf ("sync cycle failed: %v, retrying..." , err ))
252254 g .sendEvent (ctx , SyncEvent {event : of .ProviderError })
253255
0 commit comments