@@ -3,14 +3,15 @@ package flagd
33import (
44 "errors"
55 "fmt"
6+ "os"
7+ "strconv"
8+ "strings"
9+
610 "github.com/go-logr/logr"
711 "github.com/open-feature/flagd/core/pkg/sync"
812 "github.com/open-feature/go-sdk-contrib/providers/flagd/internal/cache"
913 "github.com/open-feature/go-sdk-contrib/providers/flagd/internal/logger"
1014 "google.golang.org/grpc"
11- "os"
12- "strconv"
13- "strings"
1415)
1516
1617type ResolverType string
@@ -26,6 +27,7 @@ const (
2627 defaultHost = "localhost"
2728 defaultResolver = rpc
2829 defaultGracePeriod = 5
30+ defaultFatalStatusCodes = ""
2931
3032 rpc ResolverType = "rpc"
3133 inProcess ResolverType = "in-process"
@@ -45,6 +47,7 @@ const (
4547 flagdOfflinePathEnvironmentVariableName = "FLAGD_OFFLINE_FLAG_SOURCE_PATH"
4648 flagdTargetUriEnvironmentVariableName = "FLAGD_TARGET_URI"
4749 flagdGracePeriodVariableName = "FLAGD_RETRY_GRACE_PERIOD"
50+ flagdFatalStatusCodesVariableName = "FLAGD_FATAL_STATUS_CODES"
4851)
4952
5053type ProviderConfiguration struct {
@@ -66,6 +69,7 @@ type ProviderConfiguration struct {
6669 CustomSyncProviderUri string
6770 GrpcDialOptionsOverride []grpc.DialOption
6871 RetryGracePeriod int
72+ FatalStatusCodes []string
6973
7074 log logr.Logger
7175}
@@ -130,6 +134,7 @@ func validateProviderConfiguration(p *ProviderConfiguration) error {
130134
131135// updateFromEnvVar is a utility to update configurations based on current environment variables
132136func (cfg * ProviderConfiguration ) updateFromEnvVar () {
137+
133138 portS := os .Getenv (flagdPortEnvironmentVariableName )
134139 if portS != "" {
135140 port , err := strconv .Atoi (portS )
@@ -159,17 +164,7 @@ func (cfg *ProviderConfiguration) updateFromEnvVar() {
159164 cfg .CertPath = certificatePath
160165 }
161166
162- if maxCacheSizeS := os .Getenv (flagdMaxCacheSizeEnvironmentVariableName ); maxCacheSizeS != "" {
163- maxCacheSizeFromEnv , err := strconv .Atoi (maxCacheSizeS )
164- if err != nil {
165- cfg .log .Error (err ,
166- fmt .Sprintf ("invalid env config for %s provided, using default value: %d" ,
167- flagdMaxCacheSizeEnvironmentVariableName , defaultMaxCacheSize ,
168- ))
169- } else {
170- cfg .MaxCacheSize = maxCacheSizeFromEnv
171- }
172- }
167+ cfg .MaxCacheSize = getIntFromEnvVarOrDefault (flagdMaxCacheSizeEnvironmentVariableName , defaultMaxCacheSize , cfg .log )
173168
174169 if cacheValue := os .Getenv (flagdCacheEnvironmentVariableName ); cacheValue != "" {
175170 switch cache .Type (cacheValue ) {
@@ -185,18 +180,8 @@ func (cfg *ProviderConfiguration) updateFromEnvVar() {
185180 }
186181 }
187182
188- if maxEventStreamRetriesS := os .Getenv (
189- flagdMaxEventStreamRetriesEnvironmentVariableName ); maxEventStreamRetriesS != "" {
190-
191- maxEventStreamRetries , err := strconv .Atoi (maxEventStreamRetriesS )
192- if err != nil {
193- cfg .log .Error (err ,
194- fmt .Sprintf ("invalid env config for %s provided, using default value: %d" ,
195- flagdMaxEventStreamRetriesEnvironmentVariableName , defaultMaxEventStreamRetries ))
196- } else {
197- cfg .EventStreamConnectionMaxAttempts = maxEventStreamRetries
198- }
199- }
183+ cfg .EventStreamConnectionMaxAttempts = getIntFromEnvVarOrDefault (
184+ flagdMaxEventStreamRetriesEnvironmentVariableName , defaultMaxEventStreamRetries , cfg .log )
200185
201186 if resolver := os .Getenv (flagdResolverEnvironmentVariableName ); resolver != "" {
202187 switch strings .ToLower (resolver ) {
@@ -230,12 +215,42 @@ func (cfg *ProviderConfiguration) updateFromEnvVar() {
230215 if gracePeriod := os .Getenv (flagdGracePeriodVariableName ); gracePeriod != "" {
231216 if seconds , err := strconv .Atoi (gracePeriod ); err == nil {
232217 cfg .RetryGracePeriod = seconds
233- } else {
234- // Handle parsing error
235- cfg .log .Error (err , fmt .Sprintf ("invalid grace period '%s'" , gracePeriod ))
218+ cfg .RetryGracePeriod = getIntFromEnvVarOrDefault (flagdGracePeriodVariableName , defaultGracePeriod , cfg .log )
236219 }
237220 }
238221
222+ var fatalStatusCodes string
223+ if envVal := os .Getenv (flagdFatalStatusCodesVariableName ); envVal != "" {
224+ fatalStatusCodes = envVal
225+ } else {
226+ fatalStatusCodes = defaultFatalStatusCodes
227+ }
228+ if fatalStatusCodes == "" {
229+ cfg .FatalStatusCodes = []string {}
230+ } else {
231+ fatalStatusCodesArr := strings .Split (fatalStatusCodes , "," )
232+ for i , fatalStatusCode := range fatalStatusCodesArr {
233+ fatalStatusCodesArr [i ] = strings .TrimSpace (fatalStatusCode )
234+ }
235+ cfg .FatalStatusCodes = fatalStatusCodesArr
236+ }
237+ }
238+
239+ // Helper
240+
241+ func getIntFromEnvVarOrDefault (envVarName string , defaultValue int , log logr.Logger ) int {
242+ if valueFromEnv := os .Getenv (envVarName ); valueFromEnv != "" {
243+ intValue , err := strconv .Atoi (valueFromEnv )
244+ if err != nil {
245+ log .Error (err ,
246+ fmt .Sprintf ("invalid env config for %s provided, using default value: %d" ,
247+ envVarName , defaultValue ,
248+ ))
249+ } else {
250+ return intValue
251+ }
252+ }
253+ return defaultValue
239254}
240255
241256// ProviderOptions
@@ -415,3 +430,11 @@ func WithRetryGracePeriod(gracePeriod int) ProviderOption {
415430 p .RetryGracePeriod = gracePeriod
416431 }
417432}
433+
434+ // WithFatalStatusCodes allows to set a list of gRPC status codes, which will cause streams to give up
435+ // and put the provider in a PROVIDER_FATAL state
436+ func WithFatalStatusCodes (fatalStatusCodes []string ) ProviderOption {
437+ return func (p * ProviderConfiguration ) {
438+ p .FatalStatusCodes = fatalStatusCodes
439+ }
440+ }
0 commit comments