Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
575e74c
Initial commit.
yasirfolio3 Feb 9, 2023
388bff7
Adding in memory and redis cache plugins.
yasirfolio3 Feb 10, 2023
b6c07a1
Adding tests for UPS Redis cache.
yasirfolio3 Feb 10, 2023
2417c14
WIP.
yasirfolio3 Feb 16, 2023
3913111
Add readme
yasirfolio3 Feb 18, 2023
4186605
Implementations
yasirfolio3 Mar 1, 2023
a285088
Merge branch 'master' into yasir/odp-cache
yasirfolio3 Mar 1, 2023
bf7259a
fixing unit test.
yasirfolio3 Mar 1, 2023
4565d21
headers updated.
yasirfolio3 Mar 1, 2023
24ff939
nit fixes.
yasirfolio3 Mar 2, 2023
7041091
updating go.mod
yasirfolio3 Mar 3, 2023
0f0e681
fixes to pass hadolint tests.
yasirfolio3 Mar 3, 2023
4e7ede9
Merge branch 'master' into yasir/odp-cache
yasirfolio3 Mar 3, 2023
ad2c25f
nits fixed.
yasirfolio3 Mar 3, 2023
5b53595
nits fixed.
yasirfolio3 Mar 3, 2023
fa4185c
Updated config.yaml
yasirfolio3 Mar 7, 2023
093261c
FSSDK-8970: Adds support for odp options in config. (#366)
yasirfolio3 Mar 7, 2023
44ab65c
Suggested changes made.
yasirfolio3 Mar 7, 2023
1fc7b05
Merge branch 'master' into yasir/odp-cache
yasirfolio3 Mar 7, 2023
bffb21a
Merge branch 'master' into yasir/odp-cache
yasirfolio3 Mar 13, 2023
8abfda3
suggested changes made.
yasirfolio3 Mar 13, 2023
344c849
nit fixes.
yasirfolio3 Mar 14, 2023
3cc8c71
Merge branch 'master' into yasir/odp-cache
yasirfolio3 Mar 14, 2023
ff00d6f
Merge branch 'master' into yasir/odp-cache
yasirfolio3 Mar 14, 2023
7cb5133
Added support for time units in config.yaml
yasirfolio3 Mar 17, 2023
9a49dc1
Merge branch 'master' into yasir/odp-cache
yasirfolio3 Mar 17, 2023
8a2cce0
suggested changes made.
yasirfolio3 Mar 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ Below is a comprehensive list of available configuration properties.
| client.queueSize | OPTIMIZELY_CLIENT_QUEUESIZE | The max number of events pending dispatch. Default: 1000 |
| client.sdkKeyRegex | OPTIMIZELY_CLIENT_SDKKEYREGEX | Regex to validate SDK keys provided in request header. Default: ^\\w+(:\\w+)?$ |
| client.userProfileService | OPTIMIZELY_CLIENT_USERPROFILESERVICE | Property used to enable and set UserProfileServices. Default: ./config.yaml |
| client.odp.disable | OPTIMIZELY_CLIENT_ODP_DISABLE | Property used to disable odp. Default: false |
| client.odp.eventsRequestTimeout | OPTIMIZELY_CLIENT_ODP_EVENTSREQUESTTIMEOUT | Property used to update timeout in seconds after which event requests will timeout. Default: 10s |
| client.odp.eventsFlushInterval | OPTIMIZELY_CLIENT_ODP_EVENTSFLUSHINTERVAL | Property used to update flush interval in seconds for events. Default: 1s |
| client.odp.segmentsRequestTimeout | OPTIMIZELY_CLIENT_ODP_SEGMENTSREQUESTTIMEOUT | Property used to update timeout in seconds after which segment requests will timeout: 10s |
| client.odp.cache | OPTIMIZELY_CLIENT_ODP_SEGMENTSCACHE | Property used to enable and set cache service for odp. Default: ./config.yaml |
| config.filename | OPTIMIZELY_CONFIG_FILENAME | Location of the configuration YAML file. Default: ./config.yaml |
| log.level | OPTIMIZELY_LOG_LEVEL | The log [level](https://github.com/rs/zerolog#leveled-logging) for the agent. Default: info |
| log.pretty | OPTIMIZELY_LOG_PRETTY | Flag used to set colorized console output as opposed to structured json logs. Default: false |
Expand Down Expand Up @@ -320,6 +325,10 @@ to provide a namespaced environment for custom logic. Plugins must be compiled a

- [UserProfileService](./plugins/userprofileservice/README.md) - Adds UserProfileService.

### ODPCache Plugins

- [ODPCache](./plugins/odpcache/README.md) - Adds ODP Cache.

### Authorization

Optimizely Agent supports authorization workflows based on OAuth and JWT standards, allowing you to protect access to its API and Admin interfaces. For details, see [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization).
Expand Down
9 changes: 8 additions & 1 deletion cmd/optimizely/main.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/****************************************************************************
* Copyright 2019,2022, Optimizely, Inc. and contributors *
* Copyright 2019,2022-2023 Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
Expand Down Expand Up @@ -41,6 +41,8 @@ import (

// Initiate the loading of the userprofileservice plugins
_ "github.com/optimizely/agent/plugins/userprofileservice/all"
// Initiate the loading of the odpCache plugins
_ "github.com/optimizely/agent/plugins/odpcache/all"
"github.com/optimizely/go-sdk/pkg/logging"
)

Expand Down Expand Up @@ -93,6 +95,11 @@ func loadConfig(v *viper.Viper) *config.AgentConfig {
conf.Client.UserProfileService = userProfileService
}

// Check if JSON string was set using OPTIMIZELY_CLIENT_ODP_SEGMENTSCACHE environment variable
if odpSegmentsCache := v.GetStringMap("client.odp.segmentsCache"); odpSegmentsCache != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering why we need this support for odpCache only? What about other odp config like "client.odp"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No specific reason, its just something that we did for ups aswell.

conf.Client.ODP.SegmentsCache = odpSegmentsCache
}

return conf
}

Expand Down
116 changes: 86 additions & 30 deletions cmd/optimizely/main_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/****************************************************************************
* Copyright 2019-2020,2022, Optimizely, Inc. and contributors *
* Copyright 2019-2020,2022-2023, Optimizely, Inc. and contributors *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
Expand Down Expand Up @@ -56,38 +56,61 @@ func assertServer(t *testing.T, actual config.ServerConfig, assertPlugins bool)
}
}

func assertClient(t *testing.T, actual config.ClientConfig, assertUserProfileService bool) {
func assertClient(t *testing.T, actual config.ClientConfig) {
assert.Equal(t, 10*time.Second, actual.PollingInterval)
assert.Equal(t, 1, actual.BatchSize)
assert.Equal(t, 10, actual.QueueSize)
assert.Equal(t, 1*time.Minute, actual.FlushInterval)
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)
if assertUserProfileService {
assert.Equal(t, "in-memory", actual.UserProfileService["default"])
userProfileServices := map[string]interface{}{
"in-memory": map[string]interface{}{
// Viper.set is case in-sensitive
"storagestrategy": "fifo",
},
"redis": map[string]interface{}{
"host": "localhost:6379",
"password": "",
},
"rest": map[string]interface{}{
"host": "http://localhost",
"lookuppath": "/ups/lookup",
"savepath": "/ups/save",
"headers": map[string]interface{}{"content-type": "application/json"},
"async": true,
},
"custom": map[string]interface{}{
"path": "http://test2.com",
},
}
assert.Equal(t, userProfileServices, actual.UserProfileService["services"])
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, 5*time.Second, actual.ODP.SegmentsRequestTimeout)

assert.Equal(t, "in-memory", actual.UserProfileService["default"])
userProfileServices := map[string]interface{}{
"in-memory": map[string]interface{}{
// Viper.set is case in-sensitive
"storagestrategy": "fifo",
},
"redis": map[string]interface{}{
"host": "localhost:6379",
"password": "",
},
"rest": map[string]interface{}{
"host": "http://localhost",
"lookuppath": "/ups/lookup",
"savepath": "/ups/save",
"headers": map[string]interface{}{"content-type": "application/json"},
"async": true,
},
"custom": map[string]interface{}{
"path": "http://test2.com",
},
}
assert.Equal(t, userProfileServices, actual.UserProfileService["services"])

assert.Equal(t, "in-memory", actual.ODP.SegmentsCache["default"])
odpCacheServices := map[string]interface{}{
"custom": map[string]interface{}{
"path": "http://test2.com",
},
}
actualCacheServices := actual.ODP.SegmentsCache["services"].(map[string]interface{})

assert.Equal(t, odpCacheServices["custom"], actualCacheServices["custom"])

redisCacheService := actualCacheServices["redis"].(map[string]interface{})
assert.EqualValues(t, "localhost:6379", redisCacheService["host"])
assert.EqualValues(t, "", redisCacheService["password"])
assert.EqualValues(t, "5s", redisCacheService["timeout"])
assert.EqualValues(t, "123", redisCacheService["database"])

actualInMemoryService := actualCacheServices["in-memory"].(map[string]interface{})
assert.EqualValues(t, 100, actualInMemoryService["size"])
assert.EqualValues(t, "5s", actualInMemoryService["timeout"])
}

func assertLog(t *testing.T, actual config.LogConfig) {
Expand Down Expand Up @@ -165,7 +188,7 @@ func TestViperYaml(t *testing.T) {

assertRoot(t, actual)
assertServer(t, actual.Server, true)
assertClient(t, actual.Client, true)
assertClient(t, actual.Client)
assertLog(t, actual.Log)
assertAdmin(t, actual.Admin)
assertAdminAuth(t, actual.Admin.Auth)
Expand Down Expand Up @@ -202,7 +225,7 @@ func TestViperProps(t *testing.T) {
v.Set("client.datafileURLTemplate", "https://localhost/v1/%s.json")
v.Set("client.eventURL", "https://logx.localhost.com/v1")
v.Set("client.sdkKeyRegex", "custom-regex")
services := map[string]interface{}{
upsServices := map[string]interface{}{
"in-memory": map[string]interface{}{
"storageStrategy": "fifo",
},
Expand All @@ -223,10 +246,37 @@ func TestViperProps(t *testing.T) {
}
userProfileServices := map[string]interface{}{
"default": "in-memory",
"services": services,
"services": upsServices,
}
v.Set("client.userProfileService", userProfileServices)

odpCacheServices := map[string]interface{}{
"in-memory": map[string]interface{}{
"size": 100,
"timeout": "5s",
},
"redis": map[string]interface{}{
"host": "localhost:6379",
"password": "",
"timeout": "5s",
"database": "123",
},
"custom": map[string]interface{}{
"path": "http://test2.com",
},
}
odpCache := map[string]interface{}{
"default": "in-memory",
"services": odpCacheServices,
}
odpConfig := map[string]interface{}{
"disable": true,
"eventsRequestTimeout": 5 * time.Second,
"eventsFlushInterval": 5 * time.Second,
"segmentsRequestTimeout": 5 * time.Second,
"segmentsCache": odpCache,
}
v.Set("client.odp", odpConfig)
v.Set("log.pretty", true)
v.Set("log.includeSdkKey", false)
v.Set("log.level", "debug")
Expand Down Expand Up @@ -279,7 +329,7 @@ func TestViperProps(t *testing.T) {

assertRoot(t, actual)
assertServer(t, actual.Server, true)
assertClient(t, actual.Client, true)
assertClient(t, actual.Client)
assertLog(t, actual.Log)
assertAdmin(t, actual.Admin)
assertAdminAuth(t, actual.Admin.Auth)
Expand Down Expand Up @@ -312,7 +362,13 @@ 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_SEGMENTSCACHE", `{"default":"in-memory","services":{"in-memory":{"size":100,"timeout":"5s"},"redis":{"host":"localhost:6379","password":"","timeout":"5s","database": "123"},"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_SEGMENTSREQUESTTIMEOUT", `5s`)

_ = os.Setenv("OPTIMIZELY_LOG_PRETTY", "true")
_ = os.Setenv("OPTIMIZELY_LOG_INCLUDESDKKEY", "false")
Expand Down Expand Up @@ -342,7 +398,7 @@ func TestViperEnv(t *testing.T) {

assertRoot(t, actual)
assertServer(t, actual.Server, false)
assertClient(t, actual.Client, true)
assertClient(t, actual.Client)
assertLog(t, actual.Log)
assertAdmin(t, actual.Admin)
assertAPI(t, actual.API)
Expand Down
18 changes: 18 additions & 0 deletions cmd/optimizely/testdata/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ client:
async: true
custom:
path: "http://test2.com"
odp:
disable: true
eventsRequestTimeout: 5s
eventsFlushInterval: 5s
segmentsRequestTimeout: 5s
segmentsCache:
default: "in-memory"
services:
in-memory:
size: 100
timeout: 5s
redis:
host: "localhost:6379"
password: ""
timeout: 5s
database: "123"
custom:
path: "http://test2.com"

admin:
port: "3002"
Expand Down
22 changes: 22 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,28 @@ client:
# headers:
# 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
## Timeout in seconds after which segment requests will timeout.
segmentsRequestTimeout: 10s
## If no segmentsCache is defined (or no default is defined), we will use the default in-memory with default size and timeout
segmentsCache:
default: "in-memory"
services:
in-memory:
size: 10000
timeout: 600s
# redis:
# host: "localhost:6379"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need to control redis timeout as well? We can reuse segmentsCacheTimeout but it may be confusing since we do not use segmentsCacheSize for redis.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added timeout to redis aswell.

# password: ""
# database: 0
# timeout: 0s


##
## optimizely runtime configuration can be used for debugging and profiling the go runtime.
Expand Down
Loading