@splitsoftware/splitio-commons 2.1.0-rc.2 → 2.1.1-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/CHANGES.txt +2 -7
  2. package/README.md +1 -0
  3. package/cjs/evaluator/combiners/and.js +2 -6
  4. package/cjs/evaluator/combiners/ifelseif.js +6 -6
  5. package/cjs/evaluator/condition/index.js +6 -5
  6. package/cjs/evaluator/index.js +7 -7
  7. package/cjs/evaluator/matchers/index.js +3 -1
  8. package/cjs/evaluator/matchers/matcherTypes.js +1 -0
  9. package/cjs/evaluator/matchers/rbsegment.js +43 -0
  10. package/cjs/evaluator/matchersTransform/index.js +4 -0
  11. package/cjs/evaluator/parser/index.js +2 -2
  12. package/cjs/evaluator/value/sanitize.js +1 -0
  13. package/cjs/logger/constants.js +5 -6
  14. package/cjs/logger/messages/debug.js +3 -4
  15. package/cjs/logger/messages/warn.js +1 -1
  16. package/cjs/readiness/readinessManager.js +0 -6
  17. package/cjs/services/splitApi.js +2 -2
  18. package/cjs/storages/AbstractSplitsCacheAsync.js +19 -1
  19. package/cjs/storages/AbstractSplitsCacheSync.js +17 -9
  20. package/cjs/storages/KeyBuilder.js +8 -15
  21. package/cjs/storages/KeyBuilderCS.js +11 -5
  22. package/cjs/storages/KeyBuilderSS.js +3 -0
  23. package/cjs/storages/dataLoader.js +3 -5
  24. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +117 -0
  25. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +69 -15
  26. package/cjs/storages/inLocalStorage/index.js +7 -5
  27. package/cjs/storages/inMemory/InMemoryStorage.js +3 -0
  28. package/cjs/storages/inMemory/InMemoryStorageCS.js +4 -0
  29. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +61 -0
  30. package/cjs/storages/inMemory/SplitsCacheInMemory.js +24 -31
  31. package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +64 -0
  32. package/cjs/storages/inRedis/SplitsCacheInRedis.js +4 -21
  33. package/cjs/storages/inRedis/constants.js +1 -1
  34. package/cjs/storages/inRedis/index.js +2 -0
  35. package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +64 -0
  36. package/cjs/storages/pluggable/SplitsCachePluggable.js +2 -19
  37. package/cjs/storages/pluggable/index.js +3 -2
  38. package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +14 -16
  39. package/cjs/sync/polling/fetchers/splitChangesFetcher.js +2 -2
  40. package/cjs/sync/polling/pollingManagerCS.js +7 -7
  41. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  42. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +2 -2
  43. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  44. package/cjs/sync/polling/updaters/splitChangesUpdater.js +62 -51
  45. package/cjs/sync/streaming/SSEHandler/index.js +1 -0
  46. package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +106 -77
  47. package/cjs/sync/streaming/constants.js +2 -1
  48. package/cjs/sync/streaming/pushManager.js +3 -16
  49. package/cjs/sync/syncManagerOnline.js +5 -10
  50. package/cjs/trackers/uniqueKeysTracker.js +1 -1
  51. package/cjs/utils/constants/browser.js +5 -0
  52. package/cjs/utils/constants/index.js +3 -2
  53. package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
  54. package/esm/evaluator/combiners/and.js +2 -6
  55. package/esm/evaluator/combiners/ifelseif.js +7 -7
  56. package/esm/evaluator/condition/index.js +6 -5
  57. package/esm/evaluator/index.js +7 -7
  58. package/esm/evaluator/matchers/index.js +3 -1
  59. package/esm/evaluator/matchers/matcherTypes.js +1 -0
  60. package/esm/evaluator/matchers/rbsegment.js +39 -0
  61. package/esm/evaluator/matchersTransform/index.js +4 -0
  62. package/esm/evaluator/parser/index.js +2 -2
  63. package/esm/evaluator/value/sanitize.js +1 -0
  64. package/esm/logger/constants.js +2 -3
  65. package/esm/logger/messages/debug.js +3 -4
  66. package/esm/logger/messages/warn.js +1 -1
  67. package/esm/readiness/readinessManager.js +0 -6
  68. package/esm/services/splitApi.js +2 -2
  69. package/esm/storages/AbstractSplitsCacheAsync.js +19 -1
  70. package/esm/storages/AbstractSplitsCacheSync.js +17 -9
  71. package/esm/storages/KeyBuilder.js +8 -15
  72. package/esm/storages/KeyBuilderCS.js +11 -5
  73. package/esm/storages/KeyBuilderSS.js +3 -0
  74. package/esm/storages/dataLoader.js +2 -4
  75. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +114 -0
  76. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +69 -15
  77. package/esm/storages/inLocalStorage/index.js +7 -5
  78. package/esm/storages/inMemory/InMemoryStorage.js +3 -0
  79. package/esm/storages/inMemory/InMemoryStorageCS.js +4 -0
  80. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +58 -0
  81. package/esm/storages/inMemory/SplitsCacheInMemory.js +24 -31
  82. package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +61 -0
  83. package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -21
  84. package/esm/storages/inRedis/constants.js +1 -1
  85. package/esm/storages/inRedis/index.js +2 -0
  86. package/esm/storages/pluggable/RBSegmentsCachePluggable.js +61 -0
  87. package/esm/storages/pluggable/SplitsCachePluggable.js +2 -19
  88. package/esm/storages/pluggable/index.js +3 -2
  89. package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +14 -16
  90. package/esm/sync/polling/fetchers/splitChangesFetcher.js +2 -2
  91. package/esm/sync/polling/pollingManagerCS.js +7 -7
  92. package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
  93. package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
  94. package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  95. package/esm/sync/polling/updaters/splitChangesUpdater.js +63 -52
  96. package/esm/sync/streaming/SSEHandler/index.js +2 -1
  97. package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +102 -73
  98. package/esm/sync/streaming/constants.js +1 -0
  99. package/esm/sync/streaming/pushManager.js +6 -19
  100. package/esm/sync/syncManagerOnline.js +5 -10
  101. package/esm/trackers/uniqueKeysTracker.js +1 -1
  102. package/esm/utils/constants/browser.js +2 -0
  103. package/esm/utils/constants/index.js +2 -1
  104. package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
  105. package/package.json +1 -1
  106. package/src/dtos/types.ts +32 -8
  107. package/src/evaluator/Engine.ts +1 -1
  108. package/src/evaluator/combiners/and.ts +5 -4
  109. package/src/evaluator/combiners/ifelseif.ts +7 -9
  110. package/src/evaluator/condition/engineUtils.ts +1 -1
  111. package/src/evaluator/condition/index.ts +12 -12
  112. package/src/evaluator/index.ts +7 -7
  113. package/src/evaluator/matchers/index.ts +3 -1
  114. package/src/evaluator/matchers/matcherTypes.ts +1 -0
  115. package/src/evaluator/matchers/rbsegment.ts +61 -0
  116. package/src/evaluator/matchersTransform/index.ts +3 -0
  117. package/src/evaluator/parser/index.ts +3 -3
  118. package/src/evaluator/types.ts +2 -2
  119. package/src/evaluator/value/index.ts +2 -2
  120. package/src/evaluator/value/sanitize.ts +5 -4
  121. package/src/logger/constants.ts +2 -3
  122. package/src/logger/messages/debug.ts +3 -4
  123. package/src/logger/messages/warn.ts +1 -1
  124. package/src/readiness/readinessManager.ts +0 -5
  125. package/src/sdkManager/index.ts +1 -1
  126. package/src/services/splitApi.ts +2 -2
  127. package/src/services/types.ts +1 -1
  128. package/src/storages/AbstractSplitsCacheAsync.ts +23 -5
  129. package/src/storages/AbstractSplitsCacheSync.ts +22 -15
  130. package/src/storages/KeyBuilder.ts +9 -17
  131. package/src/storages/KeyBuilderCS.ts +13 -6
  132. package/src/storages/KeyBuilderSS.ts +4 -0
  133. package/src/storages/dataLoader.ts +2 -5
  134. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +136 -0
  135. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +80 -16
  136. package/src/storages/inLocalStorage/index.ts +12 -8
  137. package/src/storages/inMemory/InMemoryStorage.ts +3 -0
  138. package/src/storages/inMemory/InMemoryStorageCS.ts +4 -0
  139. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +68 -0
  140. package/src/storages/inMemory/SplitsCacheInMemory.ts +22 -27
  141. package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +79 -0
  142. package/src/storages/inRedis/SplitsCacheInRedis.ts +4 -21
  143. package/src/storages/inRedis/constants.ts +1 -1
  144. package/src/storages/inRedis/index.ts +2 -0
  145. package/src/storages/pluggable/RBSegmentsCachePluggable.ts +76 -0
  146. package/src/storages/pluggable/SplitsCachePluggable.ts +2 -19
  147. package/src/storages/pluggable/index.ts +3 -2
  148. package/src/storages/types.ts +47 -18
  149. package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +19 -21
  150. package/src/sync/polling/fetchers/splitChangesFetcher.ts +2 -1
  151. package/src/sync/polling/fetchers/types.ts +1 -0
  152. package/src/sync/polling/pollingManagerCS.ts +7 -7
  153. package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -2
  154. package/src/sync/polling/types.ts +2 -2
  155. package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -2
  156. package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
  157. package/src/sync/polling/updaters/splitChangesUpdater.ts +74 -63
  158. package/src/sync/streaming/SSEHandler/index.ts +2 -1
  159. package/src/sync/streaming/SSEHandler/types.ts +2 -2
  160. package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +98 -68
  161. package/src/sync/streaming/constants.ts +1 -0
  162. package/src/sync/streaming/parseUtils.ts +2 -2
  163. package/src/sync/streaming/pushManager.ts +6 -18
  164. package/src/sync/streaming/types.ts +3 -2
  165. package/src/sync/syncManagerOnline.ts +5 -11
  166. package/src/trackers/uniqueKeysTracker.ts +1 -1
  167. package/src/utils/constants/browser.ts +2 -0
  168. package/src/utils/constants/index.ts +2 -1
  169. package/src/utils/lang/index.ts +2 -2
  170. package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
  171. package/types/splitio.d.ts +1 -25
  172. package/cjs/storages/inLocalStorage/validateCache.js +0 -79
  173. package/esm/storages/inLocalStorage/validateCache.js +0 -75
  174. package/src/storages/inLocalStorage/validateCache.ts +0 -91
@@ -0,0 +1,58 @@
1
+ import { setToArray } from '../../utils/lang/sets';
2
+ import { usesSegments } from '../AbstractSplitsCacheSync';
3
+ var RBSegmentsCacheInMemory = /** @class */ (function () {
4
+ function RBSegmentsCacheInMemory() {
5
+ this.cache = {};
6
+ this.changeNumber = -1;
7
+ this.segmentsCount = 0;
8
+ }
9
+ RBSegmentsCacheInMemory.prototype.clear = function () {
10
+ this.cache = {};
11
+ this.changeNumber = -1;
12
+ this.segmentsCount = 0;
13
+ };
14
+ RBSegmentsCacheInMemory.prototype.update = function (toAdd, toRemove, changeNumber) {
15
+ var _this = this;
16
+ this.changeNumber = changeNumber;
17
+ var updated = toAdd.map(function (toAdd) { return _this.add(toAdd); }).some(function (result) { return result; });
18
+ return toRemove.map(function (toRemove) { return _this.remove(toRemove.name); }).some(function (result) { return result; }) || updated;
19
+ };
20
+ RBSegmentsCacheInMemory.prototype.add = function (rbSegment) {
21
+ var name = rbSegment.name;
22
+ var previous = this.get(name);
23
+ if (previous && usesSegments(previous))
24
+ this.segmentsCount--;
25
+ this.cache[name] = rbSegment;
26
+ if (usesSegments(rbSegment))
27
+ this.segmentsCount++;
28
+ return true;
29
+ };
30
+ RBSegmentsCacheInMemory.prototype.remove = function (name) {
31
+ var rbSegment = this.get(name);
32
+ if (!rbSegment)
33
+ return false;
34
+ delete this.cache[name];
35
+ if (usesSegments(rbSegment))
36
+ this.segmentsCount--;
37
+ return true;
38
+ };
39
+ RBSegmentsCacheInMemory.prototype.getNames = function () {
40
+ return Object.keys(this.cache);
41
+ };
42
+ RBSegmentsCacheInMemory.prototype.get = function (name) {
43
+ return this.cache[name] || null;
44
+ };
45
+ RBSegmentsCacheInMemory.prototype.contains = function (names) {
46
+ var namesArray = setToArray(names);
47
+ var namesInStorage = this.getNames();
48
+ return namesArray.every(function (name) { return namesInStorage.indexOf(name) !== -1; });
49
+ };
50
+ RBSegmentsCacheInMemory.prototype.getChangeNumber = function () {
51
+ return this.changeNumber;
52
+ };
53
+ RBSegmentsCacheInMemory.prototype.usesSegments = function () {
54
+ return this.segmentsCount > 0;
55
+ };
56
+ return RBSegmentsCacheInMemory;
57
+ }());
58
+ export { RBSegmentsCacheInMemory };
@@ -22,7 +22,8 @@ var SplitsCacheInMemory = /** @class */ (function (_super) {
22
22
  this.changeNumber = -1;
23
23
  this.segmentsCount = 0;
24
24
  };
25
- SplitsCacheInMemory.prototype.addSplit = function (name, split) {
25
+ SplitsCacheInMemory.prototype.addSplit = function (split) {
26
+ var name = split.name;
26
27
  var previousSplit = this.getSplit(name);
27
28
  if (previousSplit) { // We had this Split already
28
29
  var previousTtName = previousSplit.trafficTypeName;
@@ -34,40 +35,32 @@ var SplitsCacheInMemory = /** @class */ (function (_super) {
34
35
  if (usesSegments(previousSplit))
35
36
  this.segmentsCount--;
36
37
  }
37
- if (split) {
38
- // Store the Split.
39
- this.splitsCache[name] = split;
40
- // Update TT cache
41
- var ttName = split.trafficTypeName;
42
- this.ttCache[ttName] = (this.ttCache[ttName] || 0) + 1;
43
- this.addToFlagSets(split);
44
- // Add to segments count for the new version of the Split
45
- if (usesSegments(split))
46
- this.segmentsCount++;
47
- return true;
48
- }
49
- else {
50
- return false;
51
- }
38
+ // Store the Split.
39
+ this.splitsCache[name] = split;
40
+ // Update TT cache
41
+ var ttName = split.trafficTypeName;
42
+ this.ttCache[ttName] = (this.ttCache[ttName] || 0) + 1;
43
+ this.addToFlagSets(split);
44
+ // Add to segments count for the new version of the Split
45
+ if (usesSegments(split))
46
+ this.segmentsCount++;
47
+ return true;
52
48
  };
53
49
  SplitsCacheInMemory.prototype.removeSplit = function (name) {
54
50
  var split = this.getSplit(name);
55
- if (split) {
56
- // Delete the Split
57
- delete this.splitsCache[name];
58
- var ttName = split.trafficTypeName;
59
- this.ttCache[ttName]--; // Update tt cache
60
- if (!this.ttCache[ttName])
61
- delete this.ttCache[ttName];
62
- this.removeFromFlagSets(split.name, split.sets);
63
- // Update the segments count.
64
- if (usesSegments(split))
65
- this.segmentsCount--;
66
- return true;
67
- }
68
- else {
51
+ if (!split)
69
52
  return false;
70
- }
53
+ // Delete the Split
54
+ delete this.splitsCache[name];
55
+ var ttName = split.trafficTypeName;
56
+ this.ttCache[ttName]--; // Update tt cache
57
+ if (!this.ttCache[ttName])
58
+ delete this.ttCache[ttName];
59
+ this.removeFromFlagSets(split.name, split.sets);
60
+ // Update the segments count.
61
+ if (usesSegments(split))
62
+ this.segmentsCount--;
63
+ return true;
71
64
  };
72
65
  SplitsCacheInMemory.prototype.getSplit = function (name) {
73
66
  return this.splitsCache[name] || null;
@@ -0,0 +1,61 @@
1
+ import { isNaNNumber } from '../../utils/lang';
2
+ import { LOG_PREFIX } from './constants';
3
+ import { setToArray } from '../../utils/lang/sets';
4
+ var RBSegmentsCacheInRedis = /** @class */ (function () {
5
+ function RBSegmentsCacheInRedis(log, keys, redis) {
6
+ this.log = log;
7
+ this.keys = keys;
8
+ this.redis = redis;
9
+ }
10
+ RBSegmentsCacheInRedis.prototype.get = function (name) {
11
+ return this.redis.get(this.keys.buildRBSegmentKey(name))
12
+ .then(function (maybeRBSegment) { return maybeRBSegment && JSON.parse(maybeRBSegment); });
13
+ };
14
+ RBSegmentsCacheInRedis.prototype.getNames = function () {
15
+ var _this = this;
16
+ return this.redis.keys(this.keys.searchPatternForRBSegmentKeys()).then(function (listOfKeys) { return listOfKeys.map(_this.keys.extractKey); });
17
+ };
18
+ RBSegmentsCacheInRedis.prototype.contains = function (names) {
19
+ var namesArray = setToArray(names);
20
+ return this.getNames().then(function (namesInStorage) {
21
+ return namesArray.every(function (name) { return namesInStorage.includes(name); });
22
+ });
23
+ };
24
+ RBSegmentsCacheInRedis.prototype.update = function (toAdd, toRemove, changeNumber) {
25
+ var _this = this;
26
+ return Promise.all([
27
+ this.setChangeNumber(changeNumber),
28
+ Promise.all(toAdd.map(function (toAdd) {
29
+ var key = _this.keys.buildRBSegmentKey(toAdd.name);
30
+ var stringifiedNewRBSegment = JSON.stringify(toAdd);
31
+ return _this.redis.set(key, stringifiedNewRBSegment).then(function () { return true; });
32
+ })),
33
+ Promise.all(toRemove.map(function (toRemove) {
34
+ var key = _this.keys.buildRBSegmentKey(toRemove.name);
35
+ return _this.redis.del(key).then(function (status) { return status === 1; });
36
+ }))
37
+ ]).then(function (_a) {
38
+ var added = _a[1], removed = _a[2];
39
+ return added.some(function (result) { return result; }) || removed.some(function (result) { return result; });
40
+ });
41
+ };
42
+ RBSegmentsCacheInRedis.prototype.setChangeNumber = function (changeNumber) {
43
+ return this.redis.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
44
+ };
45
+ RBSegmentsCacheInRedis.prototype.getChangeNumber = function () {
46
+ var _this = this;
47
+ return this.redis.get(this.keys.buildRBSegmentsTillKey()).then(function (value) {
48
+ var i = parseInt(value, 10);
49
+ return isNaNNumber(i) ? -1 : i;
50
+ }).catch(function (e) {
51
+ _this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from storage. Error: ' + e);
52
+ return -1;
53
+ });
54
+ };
55
+ // @TODO implement if required by DataLoader or producer mode
56
+ RBSegmentsCacheInRedis.prototype.clear = function () {
57
+ return Promise.resolve();
58
+ };
59
+ return RBSegmentsCacheInRedis;
60
+ }());
61
+ export { RBSegmentsCacheInRedis };
@@ -64,8 +64,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
64
64
  * The returned promise is resolved when the operation success
65
65
  * or rejected if it fails (e.g., redis operation fails)
66
66
  */
67
- SplitsCacheInRedis.prototype.addSplit = function (name, split) {
67
+ SplitsCacheInRedis.prototype.addSplit = function (split) {
68
68
  var _this = this;
69
+ var name = split.name;
69
70
  var splitKey = this.keys.buildSplitKey(name);
70
71
  return this.redis.get(splitKey).then(function (splitFromStorage) {
71
72
  // handling parsing error
@@ -89,18 +90,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
89
90
  }).then(function () { return _this._updateFlagSets(name, parsedPreviousSplit && parsedPreviousSplit.sets, split.sets); });
90
91
  }).then(function () { return true; });
91
92
  };
92
- /**
93
- * Add a list of splits.
94
- * The returned promise is resolved when the operation success
95
- * or rejected if it fails (e.g., redis operation fails)
96
- */
97
- SplitsCacheInRedis.prototype.addSplits = function (entries) {
98
- var _this = this;
99
- return Promise.all(entries.map(function (keyValuePair) { return _this.addSplit(keyValuePair[0], keyValuePair[1]); }));
100
- };
101
93
  /**
102
94
  * Remove a given split.
103
- * The returned promise is resolved when the operation success, with 1 or 0 indicating if the split existed or not.
95
+ * The returned promise is resolved when the operation success, with true or false indicating if the split existed (and was removed) or not.
104
96
  * or rejected if it fails (e.g., redis operation fails).
105
97
  */
106
98
  SplitsCacheInRedis.prototype.removeSplit = function (name) {
@@ -110,18 +102,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
110
102
  return _this._decrementCounts(split).then(function () { return _this._updateFlagSets(name, split.sets); });
111
103
  }
112
104
  }).then(function () {
113
- return _this.redis.del(_this.keys.buildSplitKey(name));
105
+ return _this.redis.del(_this.keys.buildSplitKey(name)).then(function (status) { return status === 1; });
114
106
  });
115
107
  };
116
- /**
117
- * Remove a list of splits.
118
- * The returned promise is resolved when the operation success,
119
- * or rejected if it fails (e.g., redis operation fails).
120
- */
121
- SplitsCacheInRedis.prototype.removeSplits = function (names) {
122
- var _this = this;
123
- return Promise.all(names.map(function (name) { return _this.removeSplit(name); }));
124
- };
125
108
  /**
126
109
  * Get split definition or null if it's not defined.
127
110
  * Returned promise is rejected if redis operation fails.
@@ -1,4 +1,4 @@
1
1
  export var LOG_PREFIX = 'storage:redis: ';
2
2
  export var DEFAULT_CACHE_SIZE = 30000;
3
- export var REFRESH_RATE = 300000; // 300.000 ms = start after 5 mins
3
+ export var REFRESH_RATE = 300000; // 300000 ms = start after 5 mins
4
4
  export var TTL_REFRESH = 3600; // 1hr
@@ -9,6 +9,7 @@ import { TelemetryCacheInRedis } from './TelemetryCacheInRedis';
9
9
  import { UniqueKeysCacheInRedis } from './UniqueKeysCacheInRedis';
10
10
  import { ImpressionCountsCacheInRedis } from './ImpressionCountsCacheInRedis';
11
11
  import { metadataBuilder } from '../utils';
12
+ import { RBSegmentsCacheInRedis } from './RBSegmentsCacheInRedis';
12
13
  /**
13
14
  * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.js
14
15
  * @see {@link https://www.npmjs.com/package/ioredis}
@@ -37,6 +38,7 @@ export function InRedisStorage(options) {
37
38
  });
38
39
  return {
39
40
  splits: new SplitsCacheInRedis(log, keys, redisClient, settings.sync.__splitFiltersValidation),
41
+ rbSegments: new RBSegmentsCacheInRedis(log, keys, redisClient),
40
42
  segments: new SegmentsCacheInRedis(log, keys, redisClient),
41
43
  impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
42
44
  impressionCounts: impressionCountsCache,
@@ -0,0 +1,61 @@
1
+ import { isNaNNumber } from '../../utils/lang';
2
+ import { LOG_PREFIX } from './constants';
3
+ import { setToArray } from '../../utils/lang/sets';
4
+ var RBSegmentsCachePluggable = /** @class */ (function () {
5
+ function RBSegmentsCachePluggable(log, keys, wrapper) {
6
+ this.log = log;
7
+ this.keys = keys;
8
+ this.wrapper = wrapper;
9
+ }
10
+ RBSegmentsCachePluggable.prototype.get = function (name) {
11
+ return this.wrapper.get(this.keys.buildRBSegmentKey(name))
12
+ .then(function (maybeRBSegment) { return maybeRBSegment && JSON.parse(maybeRBSegment); });
13
+ };
14
+ RBSegmentsCachePluggable.prototype.getNames = function () {
15
+ var _this = this;
16
+ return this.wrapper.getKeysByPrefix(this.keys.buildRBSegmentKeyPrefix()).then(function (listOfKeys) { return listOfKeys.map(_this.keys.extractKey); });
17
+ };
18
+ RBSegmentsCachePluggable.prototype.contains = function (names) {
19
+ var namesArray = setToArray(names);
20
+ return this.getNames().then(function (namesInStorage) {
21
+ return namesArray.every(function (name) { return namesInStorage.includes(name); });
22
+ });
23
+ };
24
+ RBSegmentsCachePluggable.prototype.update = function (toAdd, toRemove, changeNumber) {
25
+ var _this = this;
26
+ return Promise.all([
27
+ this.setChangeNumber(changeNumber),
28
+ Promise.all(toAdd.map(function (toAdd) {
29
+ var key = _this.keys.buildRBSegmentKey(toAdd.name);
30
+ var stringifiedNewRBSegment = JSON.stringify(toAdd);
31
+ return _this.wrapper.set(key, stringifiedNewRBSegment).then(function () { return true; });
32
+ })),
33
+ Promise.all(toRemove.map(function (toRemove) {
34
+ var key = _this.keys.buildRBSegmentKey(toRemove.name);
35
+ return _this.wrapper.del(key);
36
+ }))
37
+ ]).then(function (_a) {
38
+ var added = _a[1], removed = _a[2];
39
+ return added.some(function (result) { return result; }) || removed.some(function (result) { return result; });
40
+ });
41
+ };
42
+ RBSegmentsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
43
+ return this.wrapper.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
44
+ };
45
+ RBSegmentsCachePluggable.prototype.getChangeNumber = function () {
46
+ var _this = this;
47
+ return this.wrapper.get(this.keys.buildRBSegmentsTillKey()).then(function (value) {
48
+ var i = parseInt(value, 10);
49
+ return isNaNNumber(i) ? -1 : i;
50
+ }).catch(function (e) {
51
+ _this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from storage. Error: ' + e);
52
+ return -1;
53
+ });
54
+ };
55
+ // @TODO implement if required by DataLoader or producer mode
56
+ RBSegmentsCachePluggable.prototype.clear = function () {
57
+ return Promise.resolve();
58
+ };
59
+ return RBSegmentsCachePluggable;
60
+ }());
61
+ export { RBSegmentsCachePluggable };
@@ -51,8 +51,9 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
51
51
  * The returned promise is resolved when the operation success
52
52
  * or rejected if it fails (e.g., wrapper operation fails)
53
53
  */
54
- SplitsCachePluggable.prototype.addSplit = function (name, split) {
54
+ SplitsCachePluggable.prototype.addSplit = function (split) {
55
55
  var _this = this;
56
+ var name = split.name;
56
57
  var splitKey = this.keys.buildSplitKey(name);
57
58
  return this.wrapper.get(splitKey).then(function (splitFromStorage) {
58
59
  // handling parsing error
@@ -76,15 +77,6 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
76
77
  }).then(function () { return _this._updateFlagSets(name, parsedPreviousSplit && parsedPreviousSplit.sets, split.sets); });
77
78
  }).then(function () { return true; });
78
79
  };
79
- /**
80
- * Add a list of splits.
81
- * The returned promise is resolved when the operation success
82
- * or rejected if it fails (e.g., wrapper operation fails)
83
- */
84
- SplitsCachePluggable.prototype.addSplits = function (entries) {
85
- var _this = this;
86
- return Promise.all(entries.map(function (keyValuePair) { return _this.addSplit(keyValuePair[0], keyValuePair[1]); }));
87
- };
88
80
  /**
89
81
  * Remove a given split.
90
82
  * The returned promise is resolved when the operation success, with a boolean indicating if the split existed or not.
@@ -100,15 +92,6 @@ var SplitsCachePluggable = /** @class */ (function (_super) {
100
92
  return _this.wrapper.del(_this.keys.buildSplitKey(name));
101
93
  });
102
94
  };
103
- /**
104
- * Remove a list of splits.
105
- * The returned promise is resolved when the operation success, with a boolean array indicating if the splits existed or not.
106
- * or rejected if it fails (e.g., wrapper operation fails).
107
- */
108
- SplitsCachePluggable.prototype.removeSplits = function (names) {
109
- var _this = this;
110
- return Promise.all(names.map(function (name) { return _this.removeSplit(name); }));
111
- };
112
95
  /**
113
96
  * Get split.
114
97
  * The returned promise is resolved with the split definition or null if it's not defined,
@@ -19,6 +19,7 @@ import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
19
19
  import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
20
20
  import { metadataBuilder } from '../utils';
21
21
  import { LOG_PREFIX } from '../pluggable/constants';
22
+ import { RBSegmentsCachePluggable } from './RBSegmentsCachePluggable';
22
23
  var NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.';
23
24
  var NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.';
24
25
  /**
@@ -71,8 +72,7 @@ export function PluggableStorage(options) {
71
72
  // Connects to wrapper and emits SDK_READY event on main client
72
73
  var connectPromise = wrapper.connect().then(function () {
73
74
  if (isSynchronizer) {
74
- // @TODO reuse InLocalStorage::validateCache logic
75
- // In standalone or producer mode, clear storage if SDK key, flags filter criteria or flags spec version was modified
75
+ // In standalone or producer mode, clear storage if SDK key or feature flag filter has changed
76
76
  return wrapper.get(keys.buildHashKey()).then(function (hash) {
77
77
  var currentHash = getStorageHash(settings);
78
78
  if (hash !== currentHash) {
@@ -102,6 +102,7 @@ export function PluggableStorage(options) {
102
102
  });
103
103
  return {
104
104
  splits: new SplitsCachePluggable(log, keys, wrapper, settings.sync.__splitFiltersValidation),
105
+ rbSegments: new RBSegmentsCachePluggable(log, keys, wrapper),
105
106
  segments: new SegmentsCachePluggable(log, keys, wrapper),
106
107
  impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
107
108
  impressionCounts: impressionCountsCache,
@@ -23,30 +23,28 @@ export function fromObjectUpdaterFactory(splitsParser, storage, readiness, setti
23
23
  if (!loadError && splitsMock) {
24
24
  log.debug(SYNC_OFFLINE_DATA, [JSON.stringify(splitsMock)]);
25
25
  forOwn(splitsMock, function (val, name) {
26
- splits.push([
27
- name, {
28
- name: name,
29
- status: 'ACTIVE',
30
- killed: false,
31
- trafficAllocation: 100,
32
- defaultTreatment: CONTROL,
33
- conditions: val.conditions || [],
34
- configurations: val.configurations,
35
- trafficTypeName: val.trafficTypeName
36
- }
37
- ]);
26
+ // @ts-ignore Split changeNumber and seed is undefined in localhost mode
27
+ splits.push({
28
+ name: name,
29
+ status: 'ACTIVE',
30
+ killed: false,
31
+ trafficAllocation: 100,
32
+ defaultTreatment: CONTROL,
33
+ conditions: val.conditions || [],
34
+ configurations: val.configurations,
35
+ trafficTypeName: val.trafficTypeName
36
+ });
38
37
  });
39
38
  return Promise.all([
40
39
  splitsCache.clear(),
41
- splitsCache.addSplits(splits)
40
+ splitsCache.update(splits, [], Date.now())
42
41
  ]).then(function () {
43
42
  readiness.splits.emit(SDK_SPLITS_ARRIVED);
44
43
  if (startingUp) {
45
44
  startingUp = false;
46
- var isCacheLoaded_1 = storage.validateCache ? storage.validateCache() : false;
47
- Promise.resolve().then(function () {
45
+ Promise.resolve(splitsCache.checkCache()).then(function (cacheReady) {
48
46
  // Emits SDK_READY_FROM_CACHE
49
- if (isCacheLoaded_1)
47
+ if (cacheReady)
50
48
  readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
51
49
  // Emits SDK_READY
52
50
  readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
@@ -3,10 +3,10 @@
3
3
  * SplitChanges fetcher is a wrapper around `splitChanges` API service that parses the response and handle errors.
4
4
  */
5
5
  export function splitChangesFetcherFactory(fetchSplitChanges) {
6
- return function splitChangesFetcher(since, noCache, till,
6
+ return function splitChangesFetcher(since, noCache, till, rbSince,
7
7
  // Optional decorator for `fetchSplitChanges` promise, such as timeout or time tracker
8
8
  decorator) {
9
- var splitsPromise = fetchSplitChanges(since, noCache, till);
9
+ var splitsPromise = fetchSplitChanges(since, noCache, till, rbSince);
10
10
  if (decorator)
11
11
  splitsPromise = decorator(splitsPromise);
12
12
  return splitsPromise.then(function (resp) { return resp.json(); });
@@ -31,10 +31,10 @@ export function pollingManagerCSFactory(params) {
31
31
  readiness.splits.on(SDK_SPLITS_ARRIVED, function () {
32
32
  if (!splitsSyncTask.isRunning())
33
33
  return; // noop if not doing polling
34
- var splitsHaveSegments = storage.splits.usesSegments();
35
- if (splitsHaveSegments !== mySegmentsSyncTask.isRunning()) {
36
- log.info(POLLING_SMART_PAUSING, [splitsHaveSegments ? 'ON' : 'OFF']);
37
- if (splitsHaveSegments) {
34
+ var usingSegments = storage.splits.usesSegments() || storage.rbSegments.usesSegments();
35
+ if (usingSegments !== mySegmentsSyncTask.isRunning()) {
36
+ log.info(POLLING_SMART_PAUSING, [usingSegments ? 'ON' : 'OFF']);
37
+ if (usingSegments) {
38
38
  startMySegmentsSyncTasks();
39
39
  }
40
40
  else {
@@ -46,10 +46,10 @@ export function pollingManagerCSFactory(params) {
46
46
  var mySegmentsSyncTask = mySegmentsSyncTaskFactory(splitApi.fetchMemberships, storage, readiness, settings, matchingKey);
47
47
  // smart ready
48
48
  function smartReady() {
49
- if (!readiness.isReady() && !storage.splits.usesSegments())
49
+ if (!readiness.isReady() && !storage.splits.usesSegments() && !storage.rbSegments.usesSegments())
50
50
  readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
51
51
  }
52
- if (!storage.splits.usesSegments())
52
+ if (!storage.splits.usesSegments() && !storage.rbSegments.usesSegments())
53
53
  setTimeout(smartReady, 0);
54
54
  else
55
55
  readiness.splits.once(SDK_SPLITS_ARRIVED, smartReady);
@@ -63,7 +63,7 @@ export function pollingManagerCSFactory(params) {
63
63
  start: function () {
64
64
  log.info(POLLING_START);
65
65
  splitsSyncTask.start();
66
- if (storage.splits.usesSegments())
66
+ if (storage.splits.usesSegments() || storage.rbSegments.usesSegments())
67
67
  startMySegmentsSyncTasks();
68
68
  },
69
69
  // Stop periodic fetching (polling)
@@ -5,5 +5,5 @@ import { splitChangesUpdaterFactory } from '../updaters/splitChangesUpdater';
5
5
  * Creates a sync task that periodically executes a `splitChangesUpdater` task
6
6
  */
7
7
  export function splitsSyncTaskFactory(fetchSplitChanges, storage, readiness, settings, isClientSide) {
8
- return syncTaskFactory(settings.log, splitChangesUpdaterFactory(settings.log, splitChangesFetcherFactory(fetchSplitChanges), storage.splits, storage.segments, settings.sync.__splitFiltersValidation, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
8
+ return syncTaskFactory(settings.log, splitChangesUpdaterFactory(settings.log, splitChangesFetcherFactory(fetchSplitChanges), storage, settings.sync.__splitFiltersValidation, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
9
9
  }
@@ -9,7 +9,7 @@ import { MEMBERSHIPS_LS_UPDATE } from '../../streaming/constants';
9
9
  * - uses `segmentsEventEmitter` to emit events related to segments data updates
10
10
  */
11
11
  export function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmentsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, matchingKey) {
12
- var splits = storage.splits, segments = storage.segments, largeSegments = storage.largeSegments;
12
+ var splits = storage.splits, rbSegments = storage.rbSegments, segments = storage.segments, largeSegments = storage.largeSegments;
13
13
  var readyOnAlreadyExistentState = true;
14
14
  var startingUp = true;
15
15
  /** timeout and telemetry decorator for `splitChangesFetcher` promise */
@@ -31,7 +31,7 @@ export function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmen
31
31
  shouldNotifyUpdate = largeSegments.resetSegments(segmentsData.ls || {}) || shouldNotifyUpdate;
32
32
  }
33
33
  // Notify update if required
34
- if (splits.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
34
+ if ((splits.usesSegments() || rbSegments.usesSegments()) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
35
35
  readyOnAlreadyExistentState = false;
36
36
  segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
37
37
  }
@@ -36,7 +36,7 @@ export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segment
36
36
  * Returned promise will not be rejected.
37
37
  *
38
38
  * @param fetchOnlyNew - if true, only fetch the segments that not exists, i.e., which `changeNumber` is equal to -1.
39
- * This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE notifications.
39
+ * This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE or RB_SEGMENT_UPDATE notifications.
40
40
  * @param segmentName - segment name to fetch. By passing `undefined` it fetches the list of segments registered at the storage
41
41
  * @param noCache - true to revalidate data to fetch on a SEGMENT_UPDATE notifications.
42
42
  * @param till - till target for the provided segmentName, for CDN bypass.