-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(segment-manager): Adds implementation for ODPSegmentManager #353
Conversation
2. Suggested changes made.
…odp-segement-apimanager
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! A few changes suggested.
pkg/odp/config.go
Outdated
) | ||
|
||
// ConfigState is used to represent state of odp | ||
type ConfigState int64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it common to use int64 for a few states? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch 👍
pkg/odp/config.go
Outdated
s.lock.RLock() | ||
defer s.lock.RUnlock() | ||
value := true | ||
if s.odpServiceIntegrated == NotIntegrated { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In server-sdks, we can assume that events are sent only after datafile is parsed. So we do not need to support queueing if "NotDetermined" state (if it can make the implementation simpler).
pkg/odp/segment_option.go
Outdated
package odp | ||
|
||
// SegmentOption represents options controlling audience segments. | ||
type SegmentOption int64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type SegmentOption int64 | |
type OptimizelySegmentOption int64 |
We'll open this to public. Clients will set options for fetchSegments public api.
pkg/odp/segment_option.go
Outdated
|
||
const ( | ||
// IgnoreCache ignores cache (save/lookup) | ||
IgnoreCache SegmentOption = iota |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use this enum to public? Clients need to specify these options for fetchSegments public api.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, anything that starts with a capital letter is public in golang.
pkg/odp/segment_manager.go
Outdated
|
||
// SegmentManager represents the odp segment manager. | ||
type SegmentManager interface { | ||
FetchQualifiedSegments(userKey, userValue string, options []SegmentOption) (segments []string, err error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FetchQualifiedSegments(userKey, userValue string, options []SegmentOption) (segments []string, err error) | |
FetchQualifiedSegments(userKey, userValue string, options []OptimizelySegmentOption) (segments []string, err error) |
pkg/odp/segment_manager.go
Outdated
} | ||
|
||
// NewSegmentManager creates and returns a new instance of DefaultSegmentManager. | ||
func NewSegmentManager(cacheSize int, cacheTimeoutInSecs int64, odpConfig Config, apiManager SegmentAPIManager) *DefaultSegmentManager { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also need to support injection of custom SegmentCache (or they can specify size or timeout for default LRUCache). Server-sdks only.
pkg/odp/segment_manager.go
Outdated
|
||
// FetchQualifiedSegments fetches and returns qualified segments | ||
func (s *DefaultSegmentManager) FetchQualifiedSegments(userKey, userValue string, options []SegmentOption) (segments []string, err error) { | ||
if s.odpConfig == nil || s.odpConfig.GetAPIHost() == "" || s.odpConfig.GetAPIKey() == "" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we use odpConfig.odpServiceIntegrated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, will update this.
pkg/odp/config.go
Outdated
apiKey: apiKey, | ||
apiHost: apiHost, | ||
segmentsToCheck: segmentsToCheck, | ||
odpServiceIntegrated: NotDetermined, // initially queueing allowed until the first datafile is parsed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if we have a use case for that, but - if initial apiKey
and apiHost
are valid, then odpServiceIntegrated
is not consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have refactored it to not hold states, please have a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with a nit
@@ -38,7 +38,7 @@ type OptimizelyUserContext struct { | |||
} | |||
|
|||
// returns an instance of the optimizely user context. | |||
func newOptimizelyUserContext(optimizely *OptimizelyClient, userID string, attributes map[string]interface{}, qualifiedSegments []string, forcedDecisionService *pkgDecision.ForcedDecisionService) OptimizelyUserContext { | |||
func newOptimizelyUserContext(optimizely *OptimizelyClient, userID string, attributes map[string]interface{}, forcedDecisionService *pkgDecision.ForcedDecisionService, qualifiedSegments []string) OptimizelyUserContext { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to differentiate cloning vs new context creation (so we can send IdenfityUser event only for the first creation not for cloing). We can keep it as is and fix it later when we work on the top-level integration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what change you made for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will be adding this in a separate PR which will be focused on integrating odpManager
in userContext
.
pkg/odp/segment_manager.go
Outdated
segmentsCache: cache, | ||
} | ||
if segmentManager.segmentsCache == nil { | ||
segmentManager.segmentsCache = NewLRUCache(cacheSize, cacheTimeoutInSecs) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
segmentsCache: cache, | |
} | |
if segmentManager.segmentsCache == nil { | |
segmentManager.segmentsCache = NewLRUCache(cacheSize, cacheTimeoutInSecs) | |
} | |
segmentsCache: cache ?? NewLRUCache(cacheSize, cacheTimeoutInSecs), | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
golang does not support ternary operators such as ??
or ?:
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please address my questions before merging. lgtm
@@ -38,7 +38,7 @@ type OptimizelyUserContext struct { | |||
} | |||
|
|||
// returns an instance of the optimizely user context. | |||
func newOptimizelyUserContext(optimizely *OptimizelyClient, userID string, attributes map[string]interface{}, qualifiedSegments []string, forcedDecisionService *pkgDecision.ForcedDecisionService) OptimizelyUserContext { | |||
func newOptimizelyUserContext(optimizely *OptimizelyClient, userID string, attributes map[string]interface{}, forcedDecisionService *pkgDecision.ForcedDecisionService, qualifiedSegments []string) OptimizelyUserContext { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what change you made for this?
} | ||
|
||
// DefaultConfig represents default implementation of odp config | ||
type DefaultConfig struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i need to check name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
couldn't name this Config
as it was the name of the interface, also ODPConfig
is not recommended by linter since the config resides under odp
package. Any suggestions?
pkg/odp/config.go
Outdated
return s.apiHost | ||
} | ||
|
||
// GetSegmentsToCheck returns value for SegmentsToCheck. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you explain bit more.
pkg/odp/segment_api_manager.go
Outdated
|
||
// SegmentAPIManager represents the segment API manager. | ||
type SegmentAPIManager interface { | ||
FetchSegments(apiKey, apiHost, userKey, userValue string, segmentsToCheck []string) ([]string, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a thought, why we don't pass Config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good suggestion.
pkg/odp/segment_api_manager.go
Outdated
} | ||
|
||
// FetchSegments returns qualified ODP segments | ||
func (s *DefaultSegmentAPIManager) FetchSegments(apiKey, apiHost, userKey, userValue string, segmentsToCheck []string) ([]string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
give more proper name instead of s
pkg/odp/segment_api_manager.go
Outdated
|
||
// Creates graphql query | ||
func (s DefaultSegmentAPIManager) createRequestQuery(userKey, userValue string, segmentsToCheck []string) map[string]interface{} { | ||
query := fmt.Sprintf(`query($userId: String, $audiences: [String]) {customer(%s: $userId) {audiences(subset: $audiences) {edges {node {name state}}}}}`, userKey) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you don't need fmt.Sprintf.
Please use multiline with indentation to have more visibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String interpolation is only supported using fmt.Sprintf, will still look into it.
Summary
This PR adds support for ODPSegmentManager.
Test plan
Issues