Skip to content

Commit dbfc359

Browse files
committed
Fetch attribtes before fetch feature call
1 parent ae14323 commit dbfc359

File tree

1 file changed

+33
-19
lines changed

1 file changed

+33
-19
lines changed

growthbook.go

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,13 @@ type growthBookData struct {
3333
context *Context
3434
forcedFeatureValues map[string]interface{}
3535
attributeOverrides Attributes
36-
trackedFeatures sync.Map
37-
trackedExperiments sync.Map
36+
trackedFeatures map[string]interface{}
37+
trackedExperiments map[string]bool
3838
nextSubscriptionID subscriptionID
3939
subscriptions map[subscriptionID]ExperimentCallback
40-
assigned sync.Map
40+
assigned map[string]*Assignment
4141
ready bool
42+
finalAttributes Attributes
4243
}
4344

4445
// New creates a new GrowthBook instance.
@@ -96,11 +97,12 @@ func New(context *Context) *GrowthBook {
9697
context: context,
9798
forcedFeatureValues: nil,
9899
attributeOverrides: nil,
99-
trackedFeatures: sync.Map{},
100-
trackedExperiments: sync.Map{},
100+
trackedFeatures: make(map[string]interface{}),
101+
trackedExperiments: make(map[string]bool),
101102
nextSubscriptionID: 1,
102103
subscriptions: make(map[subscriptionID]ExperimentCallback),
103-
assigned: sync.Map{},
104+
assigned: make(map[string]*Assignment),
105+
finalAttributes: nil,
104106
}
105107
gb := &GrowthBook{inner}
106108
runtime.SetFinalizer(gb, func(gb *GrowthBook) { repoUnsubscribe(gb) })
@@ -366,6 +368,16 @@ func (gb *GrowthBook) GetFeatureValue(key string, defaultValue interface{}) inte
366368
return defaultValue
367369
}
368370

371+
// WithURL sets the URL in a GrowthBook's context.
372+
func (gb *GrowthBook) SetFinalAttributes() *GrowthBook {
373+
374+
attributes := gb.Attributes()
375+
gb.inner.Lock()
376+
gb.inner.finalAttributes = attributes
377+
defer gb.inner.Unlock()
378+
return gb
379+
}
380+
369381
// Deprecated: Use EvalFeature instead. Feature returns the result for
370382
// a feature identified by a string feature key.
371383
func (gb *GrowthBook) Feature(key string) *FeatureResult {
@@ -375,6 +387,8 @@ func (gb *GrowthBook) Feature(key string) *FeatureResult {
375387
// EvalFeature returns the result for a feature identified by a string
376388
// feature key.
377389
func (gb *GrowthBook) EvalFeature(id string) *FeatureResult {
390+
gb.inner.RLock()
391+
defer gb.inner.RUnlock()
378392

379393
// Global override.
380394
if gb.inner.forcedFeatureValues != nil {
@@ -395,7 +409,7 @@ func (gb *GrowthBook) EvalFeature(id string) *FeatureResult {
395409
for _, rule := range feature.Rules {
396410
// If the rule has a condition and the condition does not pass,
397411
// skip this rule.
398-
if rule.Condition != nil && !rule.Condition.Eval(gb.Attributes()) {
412+
if rule.Condition != nil && !rule.Condition.Eval(gb.inner.finalAttributes) {
399413
logInfo("Skip rule because of condition", id, rule)
400414
continue
401415
}
@@ -482,7 +496,7 @@ func (gb *GrowthBook) Subscribe(callback ExperimentCallback) func() {
482496

483497
// GetAllResults returns a map containing all the latest results from
484498
// all experiments that have been run, indexed by the experiment key.
485-
func (gb *GrowthBook) GetAllResults() sync.Map {
499+
func (gb *GrowthBook) GetAllResults() map[string]*Assignment {
486500
gb.inner.RLock()
487501
defer gb.inner.RUnlock()
488502

@@ -496,7 +510,7 @@ func (gb *GrowthBook) ClearSavedResults() {
496510
gb.inner.Lock()
497511
defer gb.inner.Unlock()
498512

499-
gb.inner.assigned = sync.Map{}
513+
gb.inner.assigned = make(map[string]*Assignment)
500514
}
501515

502516
// ClearTrackingData clears out records of calls to the experiment
@@ -505,7 +519,7 @@ func (gb *GrowthBook) ClearTrackingData() {
505519
gb.inner.Lock()
506520
defer gb.inner.Unlock()
507521

508-
gb.inner.trackedExperiments = sync.Map{}
522+
gb.inner.trackedExperiments = make(map[string]bool)
509523
}
510524

511525
// GetAPIInfo gets the hostname and client key for GrowthBook API
@@ -569,10 +583,10 @@ func (gb *GrowthBook) trackFeatureUsage(key string, res *FeatureResult) {
569583
}
570584

571585
// Only track a feature once, unless the assigned value changed.
572-
if saved, ok := gb.inner.trackedFeatures.Load(key); ok && reflect.DeepEqual(saved, res.Value) {
586+
if saved, ok := gb.inner.trackedFeatures[key]; ok && reflect.DeepEqual(saved, res.Value) {
573587
return
574588
}
575-
gb.inner.trackedFeatures.Store(key, res.Value)
589+
gb.inner.trackedFeatures[key] = res.Value
576590

577591
// Fire user-supplied callback
578592
if gb.inner.context.OnFeatureUsage != nil {
@@ -662,17 +676,17 @@ func (gb *GrowthBook) fireSubscriptions(exp *Experiment, result *Result) {
662676
// Determine whether the result changed from the last stored result
663677
// for the experiment.
664678
changed := false
665-
storedResult, exists := gb.inner.assigned.Load(exp.Key)
679+
storedResult, exists := gb.inner.assigned[exp.Key]
666680
if exists {
667-
storedResultAssignment := storedResult.(*Assignment)
668-
if storedResultAssignment.Result.InExperiment != result.InExperiment ||
669-
storedResultAssignment.Result.VariationID != result.VariationID {
681+
if storedResult.Result.InExperiment != result.InExperiment ||
682+
storedResult.Result.VariationID != result.VariationID {
670683
changed = true
671684
}
672685
}
673686

674687
// Store the experiment result.
675-
gb.inner.assigned.Store(exp.Key, &Assignment{exp, result})
688+
gb.inner.assigned[exp.Key] = &Assignment{exp, result}
689+
676690
// If the result changed, trigger all subscriptions.
677691
if changed || !exists {
678692
for _, sub := range gb.inner.subscriptions {
@@ -855,11 +869,11 @@ func (gb *GrowthBook) track(exp *Experiment, result *Result) {
855869
// experiment.
856870
key := result.HashAttribute + result.HashValue +
857871
exp.Key + strconv.Itoa(result.VariationID)
858-
if _, exists := gb.inner.trackedExperiments.Load(key); exists {
872+
if _, exists := gb.inner.trackedExperiments[key]; exists {
859873
return
860874
}
861875

862-
gb.inner.trackedExperiments.Store(key, true)
876+
gb.inner.trackedExperiments[key] = true
863877
gb.inner.context.TrackingCallback(exp, result)
864878
}
865879

0 commit comments

Comments
 (0)