Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit ee8ab9d

Browse files
fayyazarshadjaeopt
authored andcommitted
feat: Added caching for optimizelyConfig object (optimizely#376)
* Added cache of optimizely config until revision is updated
1 parent 60af4c5 commit ee8ab9d

File tree

4 files changed

+60
-17
lines changed

4 files changed

+60
-17
lines changed

packages/optimizely-sdk/lib/core/optimizely_config/index.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
// Get Experiment Ids which are part of rollouts
1818
function getRolloutExperimentIds(rollouts) {
19-
return rollouts.reduce(function(experimentIds, rollout) {
19+
return (rollouts || []).reduce(function(experimentIds, rollout) {
2020
rollout.experiments.forEach(function(e) {
2121
experimentIds[e.id] = true;
2222
});
@@ -27,17 +27,17 @@ function getRolloutExperimentIds(rollouts) {
2727
// Gets Map of all experiments except rollouts
2828
function getExperimentsMap(configObj) {
2929
var rolloutExperimentIds = getRolloutExperimentIds(configObj.rollouts);
30-
var featureVariablesMap = configObj.featureFlags.reduce(function(resultMap, feature){
30+
var featureVariablesMap = (configObj.featureFlags || []).reduce(function(resultMap, feature){
3131
resultMap[feature.id] = feature.variables;
3232
return resultMap;
3333
}, {});
34-
return configObj.experiments.reduce(function(experiments, experiment) {
34+
return (configObj.experiments || []).reduce(function(experiments, experiment) {
3535
// skip experiments that are part of a rollout
3636
if (!rolloutExperimentIds[experiment.id]) {
3737
experiments[experiment.key] = {
3838
id: experiment.id,
3939
key: experiment.key,
40-
variationsMap: experiment.variations.reduce(function(variations, variation) {
40+
variationsMap: (experiment.variations || []).reduce(function(variations, variation) {
4141
variations[variation.key] = {
4242
id: variation.id,
4343
key: variation.key,
@@ -59,14 +59,14 @@ function getMergedVariablesMap(configObj, variation, experimentId, featureVariab
5959
if (featureId) {
6060
var experimentFeatureVariables = featureVariablesMap[featureId];
6161
// Temporary variation variables map to get values to merge.
62-
var tempVariablesIdMap = variation.variables.reduce(function(variablesMap, variable) {
62+
var tempVariablesIdMap = (variation.variables || []).reduce(function(variablesMap, variable) {
6363
variablesMap[variable.id] = {
6464
id: variable.id,
6565
value: variable.value,
6666
};
6767
return variablesMap;
6868
}, {});
69-
variablesObject = experimentFeatureVariables.reduce(function(variablesMap, featureVariable) {
69+
variablesObject = (experimentFeatureVariables || []).reduce(function(variablesMap, featureVariable) {
7070
var variationVariable = tempVariablesIdMap[featureVariable.id];
7171
var variableValue = variation.featureEnabled && variationVariable ? variationVariable.value : featureVariable.defaultValue;
7272
variablesMap[featureVariable.key] = {
@@ -83,16 +83,16 @@ function getMergedVariablesMap(configObj, variation, experimentId, featureVariab
8383

8484
// Gets map of all experiments
8585
function getFeaturesMap(configObj, allExperiments) {
86-
return configObj.featureFlags.reduce(function(features, feature) {
86+
return (configObj.featureFlags || []).reduce(function(features, feature) {
8787
features[feature.key] = {
8888
id: feature.id,
8989
key: feature.key,
90-
experimentsMap: feature.experimentIds.reduce(function(experiments, experimentId) {
90+
experimentsMap: (feature.experimentIds || []).reduce(function(experiments, experimentId) {
9191
var experimentKey = configObj.experimentIdMap[experimentId].key;
9292
experiments[experimentKey] = allExperiments[experimentKey];
9393
return experiments;
9494
}, {}),
95-
variablesMap: feature.variables.reduce(function(variables, variable) {
95+
variablesMap: (feature.variables || []).reduce(function(variables, variable) {
9696
variables[variable.key] = {
9797
id: variable.id,
9898
key: variable.key,

packages/optimizely-sdk/lib/core/project_config/project_config_manager.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ var configValidator = require('../../utils/config_validator');
2121
var datafileManager = require('@optimizely/js-sdk-datafile-manager');
2222
var enums = require('../../utils/enums');
2323
var projectConfig = require('../../core/project_config');
24+
var optimizelyConfig = require('../optimizely_config');
2425

2526
var logger = logging.getLogger();
2627

@@ -62,6 +63,7 @@ function ProjectConfigManager(config) {
6263
logger.error(ex);
6364
this.__updateListeners = [];
6465
this.__configObj = null;
66+
this.__optimizelyConfigObj = null;
6567
this.__readyPromise = Promise.resolve({
6668
success: false,
6769
reason: getErrorMessage(ex, 'Error in initialize'),
@@ -106,6 +108,7 @@ ProjectConfigManager.prototype.__initialize = function(config) {
106108
logger: logger,
107109
skipJSONValidation: this.skipJSONValidation,
108110
});
111+
this.__optimizelyConfigObj = optimizelyConfig.getOptimizelyConfig(this.__configObj);
109112
} catch (ex) {
110113
logger.error(ex);
111114
projectConfigCreationEx = ex;
@@ -269,6 +272,7 @@ ProjectConfigManager.prototype.__handleNewConfigObj = function(newConfigObj) {
269272
}
270273

271274
this.__configObj = newConfigObj;
275+
this.__optimizelyConfigObj = optimizelyConfig.getOptimizelyConfig(newConfigObj);
272276

273277
this.__updateListeners.forEach(function(listener) {
274278
listener(newConfigObj);
@@ -282,6 +286,14 @@ ProjectConfigManager.prototype.__handleNewConfigObj = function(newConfigObj) {
282286
*/
283287
ProjectConfigManager.prototype.getConfig = function() {
284288
return this.__configObj;
289+
}
290+
291+
/**
292+
* Returns the optimizely config object
293+
* @return {Object}
294+
*/
295+
ProjectConfigManager.prototype.getOptimizelyConfig = function() {
296+
return this.__optimizelyConfigObj;
285297
};
286298

287299
/**

packages/optimizely-sdk/lib/core/project_config/project_config_manager.tests.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ var sprintf = require('@optimizely/js-sdk-utils').sprintf;
2222
var enums = require('../../utils/enums');
2323
var jsonSchemaValidator = require('../../utils/json_schema_validator');
2424
var projectConfig = require('./index');
25+
var optimizelyConfig = require('../optimizely_config/index');
2526
var projectConfigManager = require('./project_config_manager');
2627
var testData = require('../../tests/test_data');
2728

@@ -407,5 +408,36 @@ describe('lib/core/project_config/project_config_manager', function() {
407408
});
408409
});
409410
});
411+
412+
describe('test caching of optimizely config', function() {
413+
beforeEach(function() {
414+
sinon.stub(optimizelyConfig, "getOptimizelyConfig");
415+
});
416+
417+
afterEach(function() {
418+
optimizelyConfig.getOptimizelyConfig.restore();
419+
});
420+
421+
it('should return the same config until revision is changed', function() {
422+
var manager = new projectConfigManager.ProjectConfigManager({
423+
datafile: testData.getTestProjectConfig(),
424+
sdkKey: '12345',
425+
});
426+
// creating optimizely config once project config manager for the first time
427+
sinon.assert.calledOnce(optimizelyConfig.getOptimizelyConfig);
428+
// validate it should return the existing optimizely config
429+
manager.getOptimizelyConfig();
430+
sinon.assert.calledOnce(optimizelyConfig.getOptimizelyConfig);
431+
// create config with new revision
432+
var fakeDatafileManager = datafileManager.HttpPollingDatafileManager.getCall(0).returnValue;
433+
var updateListener = fakeDatafileManager.on.getCall(0).args[1];
434+
var newDatafile = testData.getTestProjectConfigWithFeatures();
435+
newDatafile.revision = '36';
436+
fakeDatafileManager.get.returns(newDatafile);
437+
updateListener({ datafile: newDatafile });
438+
// verify the optimizely config is updated
439+
sinon.assert.calledTwice(optimizelyConfig.getOptimizelyConfig);
440+
});
441+
});
410442
});
411443
});

packages/optimizely-sdk/lib/optimizely/index.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ var eventProcessor = require('@optimizely/js-sdk-event-processor');
2424
var eventTagsValidator = require('../utils/event_tags_validator');
2525
var notificationCenter = require('../core/notification_center');
2626
var projectConfig = require('../core/project_config');
27-
var optimizelyConfig = require('../core/optimizely_config');
2827
var sprintf = require('@optimizely/js-sdk-utils').sprintf;
2928
var userProfileServiceValidator = require('../utils/user_profile_service_validator');
3029
var stringValidator = require('../utils/string_value_validator');
@@ -880,8 +879,8 @@ Optimizely.prototype.getFeatureVariableString = function(featureKey, variableKey
880879

881880
/**
882881
* Returns OptimizelyConfig object containing experiments and features data
883-
* @return {Object}
884-
*
882+
* @return {Object}
883+
*
885884
* OptimizelyConfig Object Schema
886885
* {
887886
* 'experimentsMap': {
@@ -901,26 +900,26 @@ Optimizely.prototype.getFeatureVariableString = function(featureKey, variableKey
901900
* }
902901
* }
903902
* }
904-
* }
903+
* }
905904
* }
906905
* },
907906
* 'featuresMap': {
908907
* 'awesome-feature': {
909908
* 'id': '333333',
910909
* 'key': 'awesome-feature',
911910
* 'experimentsMap': Object,
912-
* 'variationsMap': Object,
913-
* }
911+
* 'variationsMap': Object,
912+
* }
914913
* }
915-
* }
914+
* }
916915
*/
917916
Optimizely.prototype.getOptimizelyConfig = function() {
918917
try {
919918
var configObj = this.projectConfigManager.getConfig();
920919
if (!configObj) {
921920
return null;
922921
}
923-
return optimizelyConfig.getOptimizelyConfig(configObj);
922+
return this.projectConfigManager.getOptimizelyConfig();
924923
} catch (e) {
925924
this.logger.log(LOG_LEVEL.ERROR, e.message);
926925
this.errorHandler.handleError(e);

0 commit comments

Comments
 (0)