@@ -42,6 +42,41 @@ type OptimizelyClient struct {
42
42
executionCtx utils.ExecutionCtx
43
43
}
44
44
45
+ // Activate returns the key of the variation the user is bucketed into and sends an impression event to the Optimizely log endpoint
46
+ func (o * OptimizelyClient ) Activate (experimentKey string , userContext entities.UserContext ) (result string , err error ) {
47
+
48
+ defer func () {
49
+ if r := recover (); r != nil {
50
+ switch t := r .(type ) {
51
+ case error :
52
+ err = t
53
+ case string :
54
+ err = errors .New (t )
55
+ default :
56
+ err = errors .New ("unexpected error" )
57
+ }
58
+ errorMessage := fmt .Sprintf ("optimizely SDK is panicking with the error:" )
59
+ logger .Error (errorMessage , err )
60
+ logger .Debug (string (debug .Stack ()))
61
+ }
62
+ }()
63
+
64
+ decisionContext , experimentDecision , err := o .getExperimentDecision (experimentKey , userContext )
65
+ if err != nil {
66
+ logger .Error ("received an error while computing experiment decision" , err )
67
+ return result , err
68
+ }
69
+
70
+ if experimentDecision .Variation != nil {
71
+ // send an impression event
72
+ result = experimentDecision .Variation .Key
73
+ impressionEvent := event .CreateImpressionUserEvent (decisionContext .ProjectConfig , * decisionContext .Experiment , * experimentDecision .Variation , userContext )
74
+ o .EventProcessor .ProcessEvent (impressionEvent )
75
+ }
76
+
77
+ return result , err
78
+ }
79
+
45
80
// IsFeatureEnabled returns true if the feature is enabled for the given user
46
81
func (o * OptimizelyClient ) IsFeatureEnabled (featureKey string , userContext entities.UserContext ) (result bool , err error ) {
47
82
@@ -124,45 +159,6 @@ func (o *OptimizelyClient) GetEnabledFeatures(userContext entities.UserContext)
124
159
return enabledFeatures , err
125
160
}
126
161
127
- // Track take and event key with event tags and if the event is part of the config, send to events backend.
128
- func (o * OptimizelyClient ) Track (eventKey string , userContext entities.UserContext , eventTags map [string ]interface {}) (err error ) {
129
-
130
- defer func () {
131
- if r := recover (); r != nil {
132
- switch t := r .(type ) {
133
- case error :
134
- err = t
135
- case string :
136
- err = errors .New (t )
137
- default :
138
- err = errors .New ("unexpected error" )
139
- }
140
- errorMessage := fmt .Sprintf ("optimizely SDK is panicking with the error:" )
141
- logger .Error (errorMessage , err )
142
- logger .Debug (string (debug .Stack ()))
143
- }
144
- }()
145
-
146
- projectConfig , err := o .GetProjectConfig ()
147
- if err != nil {
148
- logger .Error ("Optimizely SDK tracking error" , err )
149
- return err
150
- }
151
-
152
- configEvent , err := projectConfig .GetEventByKey (eventKey )
153
-
154
- if err == nil {
155
- userEvent := event .CreateConversionUserEvent (projectConfig , configEvent , userContext , eventTags )
156
- o .EventProcessor .ProcessEvent (userEvent )
157
- } else {
158
- errorMessage := fmt .Sprintf (`optimizely SDK track: error getting event with key "%s"` , eventKey )
159
- logger .Error (errorMessage , err )
160
- return err
161
- }
162
-
163
- return err
164
- }
165
-
166
162
// GetFeatureVariableBoolean returns boolean feature variable value
167
163
func (o * OptimizelyClient ) GetFeatureVariableBoolean (featureKey , variableKey string , userContext entities.UserContext ) (value bool , err error ) {
168
164
@@ -364,43 +360,106 @@ func (o *OptimizelyClient) GetAllFeatureVariables(featureKey string, userContext
364
360
return enabled , variableMap , err
365
361
}
366
362
367
- func (o * OptimizelyClient ) getFeatureDecision (featureKey string , userContext entities.UserContext ) (decisionContext decision.FeatureDecisionContext , featureDecision decision.FeatureDecision , err error ) {
363
+ // GetVariation returns the key of the variation the user is bucketed into
364
+ func (o * OptimizelyClient ) GetVariation (experimentKey string , userContext entities.UserContext ) (result string , err error ) {
368
365
369
366
defer func () {
370
- var e error
371
367
if r := recover (); r != nil {
372
368
switch t := r .(type ) {
373
369
case error :
374
- e = t
370
+ err = t
375
371
case string :
376
- e = errors .New (t )
372
+ err = errors .New (t )
377
373
default :
378
- e = errors .New ("unexpected error" )
374
+ err = errors .New ("unexpected error" )
379
375
}
380
376
errorMessage := fmt .Sprintf ("optimizely SDK is panicking with the error:" )
381
- logger .Error (errorMessage , e )
377
+ logger .Error (errorMessage , err )
382
378
logger .Debug (string (debug .Stack ()))
379
+ }
380
+ }()
383
381
384
- // If we have a feature, then we can recover w/o throwing
385
- if decisionContext .Feature == nil {
386
- err = e
382
+ _ , experimentDecision , err := o .getExperimentDecision (experimentKey , userContext )
383
+ if err != nil {
384
+ logger .Error ("received an error while computing experiment decision" , err )
385
+ }
386
+
387
+ if experimentDecision .Variation != nil {
388
+ result = experimentDecision .Variation .Key
389
+ }
390
+
391
+ return result , err
392
+ }
393
+
394
+ // Track take and event key with event tags and if the event is part of the config, send to events backend.
395
+ func (o * OptimizelyClient ) Track (eventKey string , userContext entities.UserContext , eventTags map [string ]interface {}) (err error ) {
396
+
397
+ defer func () {
398
+ if r := recover (); r != nil {
399
+ switch t := r .(type ) {
400
+ case error :
401
+ err = t
402
+ case string :
403
+ err = errors .New (t )
404
+ default :
405
+ err = errors .New ("unexpected error" )
406
+ }
407
+ errorMessage := fmt .Sprintf ("optimizely SDK is panicking with the error:" )
408
+ logger .Error (errorMessage , err )
409
+ logger .Debug (string (debug .Stack ()))
410
+ }
411
+ }()
412
+
413
+ projectConfig , e := o .GetProjectConfig ()
414
+ if e != nil {
415
+ logger .Error ("Optimizely SDK tracking error" , e )
416
+ return e
417
+ }
418
+
419
+ configEvent , e := projectConfig .GetEventByKey (eventKey )
420
+
421
+ if e != nil {
422
+ errorMessage := fmt .Sprintf (`optimizely SDK track: error getting event with key "%s"` , eventKey )
423
+ logger .Error (errorMessage , e )
424
+ return e
425
+ }
426
+
427
+ userEvent := event .CreateConversionUserEvent (projectConfig , configEvent , userContext , eventTags )
428
+ o .EventProcessor .ProcessEvent (userEvent )
429
+ return nil
430
+ }
431
+
432
+ func (o * OptimizelyClient ) getFeatureDecision (featureKey string , userContext entities.UserContext ) (decisionContext decision.FeatureDecisionContext , featureDecision decision.FeatureDecision , err error ) {
433
+
434
+ defer func () {
435
+ if r := recover (); r != nil {
436
+ switch t := r .(type ) {
437
+ case error :
438
+ err = t
439
+ case string :
440
+ err = errors .New (t )
441
+ default :
442
+ err = errors .New ("unexpected error" )
387
443
}
444
+ errorMessage := fmt .Sprintf ("optimizely SDK is panicking with the error:" )
445
+ logger .Error (errorMessage , err )
446
+ logger .Debug (string (debug .Stack ()))
388
447
}
389
448
}()
390
449
391
450
userID := userContext .ID
392
451
logger .Debug (fmt .Sprintf (`Evaluating feature "%s" for user "%s".` , featureKey , userID ))
393
452
394
- projectConfig , err := o .GetProjectConfig ()
395
- if err != nil {
396
- logger .Error ("Error calling getFeatureDecision" , err )
397
- return decisionContext , featureDecision , err
453
+ projectConfig , e := o .GetProjectConfig ()
454
+ if e != nil {
455
+ logger .Error ("Error calling getFeatureDecision" , e )
456
+ return decisionContext , featureDecision , e
398
457
}
399
458
400
- feature , err := projectConfig .GetFeatureByKey (featureKey )
401
- if err != nil {
402
- logger .Error ("Error calling getFeatureDecision" , err )
403
- return decisionContext , featureDecision , err
459
+ feature , e := projectConfig .GetFeatureByKey (featureKey )
460
+ if e != nil {
461
+ logger .Error ("Error calling getFeatureDecision" , e )
462
+ return decisionContext , featureDecision , e
404
463
}
405
464
406
465
decisionContext = decision.FeatureDecisionContext {
@@ -410,15 +469,51 @@ func (o *OptimizelyClient) getFeatureDecision(featureKey string, userContext ent
410
469
411
470
featureDecision , err = o .DecisionService .GetFeatureDecision (decisionContext , userContext )
412
471
if err != nil {
413
- err = nil
414
472
logger .Warning ("error making a decision" )
415
473
return decisionContext , featureDecision , err
416
474
}
417
475
418
- // @TODO(yasir): send decision notification
419
476
return decisionContext , featureDecision , err
420
477
}
421
478
479
+ func (o * OptimizelyClient ) getExperimentDecision (experimentKey string , userContext entities.UserContext ) (decisionContext decision.ExperimentDecisionContext , experimentDecision decision.ExperimentDecision , err error ) {
480
+
481
+ userID := userContext .ID
482
+ logger .Debug (fmt .Sprintf (`Evaluating experiment "%s" for user "%s".` , experimentKey , userID ))
483
+
484
+ projectConfig , e := o .GetProjectConfig ()
485
+ if e != nil {
486
+ logger .Error ("Error calling getExperimentDecision" , e )
487
+ return decisionContext , experimentDecision , e
488
+ }
489
+
490
+ experiment , e := projectConfig .GetExperimentByKey (experimentKey )
491
+ if e != nil {
492
+ logger .Error ("Error calling getExperimentDecision" , e )
493
+ return decisionContext , experimentDecision , e
494
+ }
495
+
496
+ decisionContext = decision.ExperimentDecisionContext {
497
+ Experiment : & experiment ,
498
+ ProjectConfig : projectConfig ,
499
+ }
500
+
501
+ experimentDecision , err = o .DecisionService .GetExperimentDecision (decisionContext , userContext )
502
+ if err != nil {
503
+ logger .Warning (fmt .Sprintf (`error making a decision for experiment "%s"` , experimentKey ))
504
+ return decisionContext , experimentDecision , err
505
+ }
506
+
507
+ if experimentDecision .Variation != nil {
508
+ result := experimentDecision .Variation .Key
509
+ logger .Info (fmt .Sprintf (`User "%s" is bucketed into variation "%s" of experiment "%s".` , userContext .ID , result , experimentKey ))
510
+ } else {
511
+ logger .Info (fmt .Sprintf (`User "%s" is not bucketed into any variation for experiment "%s".` , userContext .ID , experimentKey ))
512
+ }
513
+
514
+ return decisionContext , experimentDecision , err
515
+ }
516
+
422
517
// GetProjectConfig returns the current ProjectConfig or nil if the instance is not valid
423
518
func (o * OptimizelyClient ) GetProjectConfig () (projectConfig optimizely.ProjectConfig , err error ) {
424
519
0 commit comments