diff --git a/cmd/optimizely/main_test.go b/cmd/optimizely/main_test.go index 1b47542c..8928982b 100644 --- a/cmd/optimizely/main_test.go +++ b/cmd/optimizely/main_test.go @@ -64,6 +64,12 @@ func assertClient(t *testing.T, actual config.ClientConfig) { assert.Equal(t, "https://localhost/v1/%s.json", actual.DatafileURLTemplate) assert.Equal(t, "https://logx.localhost.com/v1", actual.EventURL) assert.Equal(t, "custom-regex", actual.SdkKeyRegex) + assert.True(t, actual.ODP.Disable) + assert.Equal(t, 5*time.Second, actual.ODP.EventsFlushInterval) + assert.Equal(t, 5*time.Second, actual.ODP.EventsRequestTimeout) + assert.Equal(t, 100, actual.ODP.SegmentsCacheSize) + assert.Equal(t, 1*time.Minute, actual.ODP.SegmentsCacheTimeout) + assert.Equal(t, 5*time.Second, actual.ODP.SegmentsRequestTimeout) assert.Equal(t, "in-memory", actual.UserProfileService["default"]) userProfileServices := map[string]interface{}{ @@ -262,8 +268,16 @@ func TestViperProps(t *testing.T) { "default": "in-memory", "services": odpCacheServices, } - v.Set("client.odp.cache", odpCache) - + odpConfig := map[string]interface{}{ + "disable": true, + "eventsRequestTimeout": 5 * time.Second, + "eventsFlushInterval": 5 * time.Second, + "segmentsCacheSize": 100, + "segmentsCacheTimeout": 1 * time.Minute, + "segmentsRequestTimeout": 5 * time.Second, + "cache": odpCache, + } + v.Set("client.odp", odpConfig) v.Set("log.pretty", true) v.Set("log.includeSdkKey", false) v.Set("log.level", "debug") @@ -349,8 +363,15 @@ func TestViperEnv(t *testing.T) { _ = os.Setenv("OPTIMIZELY_CLIENT_DATAFILEURLTEMPLATE", "https://localhost/v1/%s.json") _ = os.Setenv("OPTIMIZELY_CLIENT_EVENTURL", "https://logx.localhost.com/v1") _ = os.Setenv("OPTIMIZELY_CLIENT_SDKKEYREGEX", "custom-regex") + _ = os.Setenv("OPTIMIZELY_CLIENT_USERPROFILESERVICE", `{"default":"in-memory","services":{"in-memory":{"storagestrategy":"fifo"},"redis":{"host":"localhost:6379","password":""},"rest":{"host":"http://localhost","lookuppath":"/ups/lookup","savepath":"/ups/save","headers":{"content-type":"application/json"},"async":true},"custom":{"path":"http://test2.com"}}}`) _ = os.Setenv("OPTIMIZELY_CLIENT_ODP_CACHE", `{"default":"in-memory","services":{"in-memory":{"size":100,"timeout":5},"redis":{"host":"localhost:6379","password":""},"custom":{"path":"http://test2.com"}}}`) + _ = os.Setenv("OPTIMIZELY_CLIENT_ODP_DISABLE", `true`) + _ = os.Setenv("OPTIMIZELY_CLIENT_ODP_EVENTSREQUESTTIMEOUT", `5s`) + _ = os.Setenv("OPTIMIZELY_CLIENT_ODP_EVENTSFLUSHINTERVAL", `5s`) + _ = os.Setenv("OPTIMIZELY_CLIENT_ODP_SEGMENTSCACHESIZE", `100`) + _ = os.Setenv("OPTIMIZELY_CLIENT_ODP_SEGMENTSCACHETIMEOUT", `1m`) + _ = os.Setenv("OPTIMIZELY_CLIENT_ODP_SEGMENTSREQUESTTIMEOUT", `5s`) _ = os.Setenv("OPTIMIZELY_LOG_PRETTY", "true") _ = os.Setenv("OPTIMIZELY_LOG_INCLUDESDKKEY", "false") diff --git a/cmd/optimizely/testdata/default.yaml b/cmd/optimizely/testdata/default.yaml index 94526a1c..3cd43c53 100644 --- a/cmd/optimizely/testdata/default.yaml +++ b/cmd/optimizely/testdata/default.yaml @@ -50,6 +50,12 @@ client: custom: path: "http://test2.com" odp: + disable: true + eventsRequestTimeout: 5s + eventsFlushInterval: 5s + segmentsCacheSize: 100 + segmentsCacheTimeout: 1m + segmentsRequestTimeout: 5s cache: default: "in-memory" services: diff --git a/config.yaml b/config.yaml index 12e26d48..9ac4e090 100644 --- a/config.yaml +++ b/config.yaml @@ -158,6 +158,19 @@ client: # Content-Type: "application/json" # Auth-Token: "12345" odp: + ## Disable odp + disable: false + ## Timeout in seconds after which event requests will timeout. + eventsRequestTimeout: 10s + ## Flush interval in seconds for odp events + eventsFlushInterval: 1s + ## Max number of items that can be stored in odp segments cache. + segmentsCacheSize: 10000 + ## Timeout in seconds after which an item stored in odp segments cache will be deleted. + segmentsCacheTimeout: 600s + ## Timeout in seconds after which segment requests will timeout. + segmentsRequestTimeout: 10s + ## This will override all other settings cache: default: "" services: diff --git a/config/config.go b/config/config.go index 777903f4..845d147f 100644 --- a/config/config.go +++ b/config/config.go @@ -84,6 +84,12 @@ func NewDefaultConfig() *AgentConfig { "services": map[string]interface{}{}, }, ODP: OdpConfig{ + Disable: false, + EventsRequestTimeout: 10 * time.Second, + EventsFlushInterval: 1 * time.Second, + SegmentsCacheSize: 10000, + SegmentsCacheTimeout: 600 * time.Second, + SegmentsRequestTimeout: 10 * time.Second, Cache: ODPCacheConfigs{ "default": "", "services": map[string]interface{}{}, @@ -177,7 +183,13 @@ type ClientConfig struct { // OdpConfig holds the odp configuration type OdpConfig struct { - Cache ODPCacheConfigs `json:"cache"` + EventsRequestTimeout time.Duration `json:"eventsRequestTimeout"` + EventsFlushInterval time.Duration `json:"eventsFlushInterval"` + Disable bool `json:"disable"` + SegmentsCacheSize int `json:"segmentsCacheSize"` + SegmentsCacheTimeout time.Duration `json:"segmentsCacheTimeout"` + SegmentsRequestTimeout time.Duration `json:"segmentsRequestTimeout"` + Cache ODPCacheConfigs `json:"cache"` } // LogConfig holds the log configuration diff --git a/config/config_test.go b/config/config_test.go index a4d4f412..6192c17b 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -83,6 +83,12 @@ func TestDefaultConfig(t *testing.T) { assert.Equal(t, "https://logx.optimizely.com/v1/events", conf.Client.EventURL) assert.Equal(t, "^\\w+(:\\w+)?$", conf.Client.SdkKeyRegex) assert.Equal(t, "", conf.Client.UserProfileService["default"]) + assert.Equal(t, false, conf.Client.ODP.Disable) + assert.Equal(t, 1*time.Second, conf.Client.ODP.EventsFlushInterval) + assert.Equal(t, 10*time.Second, conf.Client.ODP.EventsRequestTimeout) + assert.Equal(t, 10000, conf.Client.ODP.SegmentsCacheSize) + assert.Equal(t, 600*time.Second, conf.Client.ODP.SegmentsCacheTimeout) + assert.Equal(t, 10*time.Second, conf.Client.ODP.SegmentsRequestTimeout) assert.Equal(t, map[string]interface{}{}, conf.Client.UserProfileService["services"]) assert.Equal(t, "", conf.Client.ODP.Cache["default"]) assert.Equal(t, map[string]interface{}{}, conf.Client.ODP.Cache["services"]) diff --git a/pkg/optimizely/cache.go b/pkg/optimizely/cache.go index 76931d03..4c4fbd8e 100644 --- a/pkg/optimizely/cache.go +++ b/pkg/optimizely/cache.go @@ -33,7 +33,9 @@ import ( "github.com/optimizely/go-sdk/pkg/decision" "github.com/optimizely/go-sdk/pkg/event" "github.com/optimizely/go-sdk/pkg/odp" + odpEventPkg "github.com/optimizely/go-sdk/pkg/odp/event" odpSegmentPkg "github.com/optimizely/go-sdk/pkg/odp/segment" + "github.com/optimizely/go-sdk/pkg/utils" odpCachePkg "github.com/optimizely/go-sdk/pkg/odp/cache" cmap "github.com/orcaman/concurrent-map" @@ -242,6 +244,7 @@ func defaultLoader( client.WithConfigManager(configManager), client.WithExperimentOverrides(forcedVariations), client.WithEventProcessor(ep), + client.WithOdpDisabled(conf.ODP.Disable), } var clientUserProfileService decision.UserProfileService @@ -262,15 +265,39 @@ func defaultLoader( // convert odpCache to Cache interface if convertedODPCache, ok := rawODPCache.(odpCachePkg.Cache); ok && convertedODPCache != nil { clientODPCache = convertedODPCache - odpSegmentOptions := []odpSegmentPkg.SMOptionFunc{odpSegmentPkg.WithSegmentsCache(clientODPCache)} - segmentManager := odpSegmentPkg.NewSegmentManager(sdkKey, odpSegmentOptions...) - odpOptions := []odp.OMOptionFunc{odp.WithSegmentManager(segmentManager)} - odpManager := odp.NewOdpManager(sdkKey, - false, odpOptions...) - clientOptions = append(clientOptions, client.WithOdpManager(odpManager)) } } + // Create segment manager with odpConfig and custom cache + segmentManager := odpSegmentPkg.NewSegmentManager( + sdkKey, + odpSegmentPkg.WithAPIManager( + odpSegmentPkg.NewSegmentAPIManager(sdkKey, utils.NewHTTPRequester(nil, utils.Timeout(conf.ODP.SegmentsRequestTimeout))), + ), + odpSegmentPkg.WithSegmentsCacheSize(conf.ODP.SegmentsCacheSize), + odpSegmentPkg.WithSegmentsCacheTimeout(conf.ODP.SegmentsCacheTimeout), + odpSegmentPkg.WithSegmentsCache(clientODPCache), + ) + + // Create event manager with odpConfig + eventManager := odpEventPkg.NewBatchEventManager( + odpEventPkg.WithAPIManager( + odpEventPkg.NewEventAPIManager( + sdkKey, utils.NewHTTPRequester(nil, utils.Timeout(conf.ODP.EventsRequestTimeout)), + ), + ), + odpEventPkg.WithFlushInterval(conf.ODP.EventsFlushInterval), + ) + + // Create odp manager with custom segment and event manager + odpManager := odp.NewOdpManager( + sdkKey, + conf.ODP.Disable, + odp.WithSegmentManager(segmentManager), + odp.WithEventManager(eventManager), + ) + clientOptions = append(clientOptions, client.WithOdpManager(odpManager)) + optimizelyClient, err := optimizelyFactory.Client( clientOptions..., ) diff --git a/pkg/optimizely/cache_test.go b/pkg/optimizely/cache_test.go index 1f3042c9..8813b734 100644 --- a/pkg/optimizely/cache_test.go +++ b/pkg/optimizely/cache_test.go @@ -407,12 +407,18 @@ func (s *DefaultLoaderTestSuite) TestDefaultLoader() { }}, }, ODP: config.OdpConfig{ + EventsRequestTimeout: 10 * time.Second, + EventsFlushInterval: 1 * time.Second, Cache: map[string]interface{}{"default": "in-memory", "services": map[string]interface{}{ "in-memory": map[string]interface{}{ "size": 100, "timeout": 5, }}, }, + Disable: true, + SegmentsCacheTimeout: 5 * time.Minute, + SegmentsCacheSize: 100, + SegmentsRequestTimeout: 10 * time.Second, }, }