@splitsoftware/splitio-commons 2.8.0 → 2.8.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 (36) hide show
  1. package/CHANGES.txt +4 -0
  2. package/cjs/storages/AbstractMySegmentsCacheSync.js +31 -23
  3. package/cjs/storages/AbstractSplitsCacheSync.js +3 -2
  4. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +10 -28
  5. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +22 -33
  6. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +19 -29
  7. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +3 -2
  8. package/cjs/storages/inRedis/SegmentsCacheInRedis.js +1 -1
  9. package/cjs/sync/polling/syncTasks/segmentsSyncTask.js +1 -1
  10. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +2 -2
  11. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +16 -5
  12. package/cjs/sync/polling/updaters/splitChangesUpdater.js +3 -3
  13. package/esm/storages/AbstractMySegmentsCacheSync.js +31 -23
  14. package/esm/storages/AbstractSplitsCacheSync.js +3 -2
  15. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +11 -29
  16. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +22 -33
  17. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +19 -29
  18. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +3 -2
  19. package/esm/storages/inRedis/SegmentsCacheInRedis.js +1 -1
  20. package/esm/sync/polling/syncTasks/segmentsSyncTask.js +1 -1
  21. package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
  22. package/esm/sync/polling/updaters/segmentChangesUpdater.js +16 -5
  23. package/esm/sync/polling/updaters/splitChangesUpdater.js +3 -3
  24. package/package.json +1 -1
  25. package/src/storages/AbstractMySegmentsCacheSync.ts +26 -20
  26. package/src/storages/AbstractSplitsCacheSync.ts +3 -2
  27. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +9 -24
  28. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +18 -27
  29. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +22 -29
  30. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +3 -2
  31. package/src/storages/inRedis/SegmentsCacheInRedis.ts +1 -1
  32. package/src/sync/polling/syncTasks/segmentsSyncTask.ts +2 -0
  33. package/src/sync/polling/updaters/mySegmentsUpdater.ts +3 -3
  34. package/src/sync/polling/updaters/segmentChangesUpdater.ts +17 -4
  35. package/src/sync/polling/updaters/splitChangesUpdater.ts +6 -7
  36. package/types/splitio.d.ts +0 -2
@@ -15,9 +15,10 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
15
15
  };
16
16
  RBSegmentsCacheInLocal.prototype.update = function (toAdd, toRemove, changeNumber) {
17
17
  var _this = this;
18
- this.setChangeNumber(changeNumber);
19
18
  var updated = toAdd.map(function (toAdd) { return _this.add(toAdd); }).some(function (result) { return result; });
20
- return toRemove.map(function (toRemove) { return _this.remove(toRemove.name); }).some(function (result) { return result; }) || updated;
19
+ updated = toRemove.map(function (toRemove) { return _this.remove(toRemove.name); }).some(function (result) { return result; }) || updated;
20
+ this.setChangeNumber(changeNumber);
21
+ return updated;
21
22
  };
22
23
  RBSegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
23
24
  try {
@@ -37,40 +38,28 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
37
38
  this.storage.removeItem(segmentsCountKey);
38
39
  };
39
40
  RBSegmentsCacheInLocal.prototype.add = function (rbSegment) {
40
- try {
41
- var name_1 = rbSegment.name;
42
- var rbSegmentKey = this.keys.buildRBSegmentKey(name_1);
43
- var rbSegmentFromStorage = this.storage.getItem(rbSegmentKey);
44
- var previous = rbSegmentFromStorage ? JSON.parse(rbSegmentFromStorage) : null;
45
- this.storage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
46
- var usesSegmentsDiff = 0;
47
- if (previous && usesSegments(previous))
48
- usesSegmentsDiff--;
49
- if (usesSegments(rbSegment))
50
- usesSegmentsDiff++;
51
- if (usesSegmentsDiff !== 0)
52
- this.updateSegmentCount(usesSegmentsDiff);
53
- return true;
54
- }
55
- catch (e) {
56
- this.log.error(LOG_PREFIX + e);
57
- return false;
58
- }
41
+ var name = rbSegment.name;
42
+ var rbSegmentKey = this.keys.buildRBSegmentKey(name);
43
+ var rbSegmentFromStorage = this.storage.getItem(rbSegmentKey);
44
+ var previous = rbSegmentFromStorage ? JSON.parse(rbSegmentFromStorage) : null;
45
+ this.storage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
46
+ var usesSegmentsDiff = 0;
47
+ if (previous && usesSegments(previous))
48
+ usesSegmentsDiff--;
49
+ if (usesSegments(rbSegment))
50
+ usesSegmentsDiff++;
51
+ if (usesSegmentsDiff !== 0)
52
+ this.updateSegmentCount(usesSegmentsDiff);
53
+ return true;
59
54
  };
60
55
  RBSegmentsCacheInLocal.prototype.remove = function (name) {
61
- try {
62
- var rbSegment = this.get(name);
63
- if (!rbSegment)
64
- return false;
65
- this.storage.removeItem(this.keys.buildRBSegmentKey(name));
66
- if (usesSegments(rbSegment))
67
- this.updateSegmentCount(-1);
68
- return true;
69
- }
70
- catch (e) {
71
- this.log.error(LOG_PREFIX + e);
56
+ var rbSegment = this.get(name);
57
+ if (!rbSegment)
72
58
  return false;
73
- }
59
+ this.storage.removeItem(this.keys.buildRBSegmentKey(name));
60
+ if (usesSegments(rbSegment))
61
+ this.updateSegmentCount(-1);
62
+ return true;
74
63
  };
75
64
  RBSegmentsCacheInLocal.prototype.getNames = function () {
76
65
  var len = this.storage.length;
@@ -67,39 +67,27 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
67
67
  this.hasSync = false;
68
68
  };
69
69
  SplitsCacheInLocal.prototype.addSplit = function (split) {
70
- try {
71
- var name_1 = split.name;
72
- var splitKey = this.keys.buildSplitKey(name_1);
73
- var splitFromStorage = this.storage.getItem(splitKey);
74
- var previousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : null;
75
- if (previousSplit) {
76
- this._decrementCounts(previousSplit);
77
- this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
78
- }
79
- this.storage.setItem(splitKey, JSON.stringify(split));
80
- this._incrementCounts(split);
81
- this.addToFlagSets(split);
82
- return true;
83
- }
84
- catch (e) {
85
- this.log.error(LOG_PREFIX + e);
86
- return false;
70
+ var name = split.name;
71
+ var splitKey = this.keys.buildSplitKey(name);
72
+ var splitFromStorage = this.storage.getItem(splitKey);
73
+ var previousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : null;
74
+ if (previousSplit) {
75
+ this._decrementCounts(previousSplit);
76
+ this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
87
77
  }
78
+ this.storage.setItem(splitKey, JSON.stringify(split));
79
+ this._incrementCounts(split);
80
+ this.addToFlagSets(split);
81
+ return true;
88
82
  };
89
83
  SplitsCacheInLocal.prototype.removeSplit = function (name) {
90
- try {
91
- var split = this.getSplit(name);
92
- if (!split)
93
- return false;
94
- this.storage.removeItem(this.keys.buildSplitKey(name));
95
- this._decrementCounts(split);
96
- this.removeFromFlagSets(split.name, split.sets);
97
- return true;
98
- }
99
- catch (e) {
100
- this.log.error(LOG_PREFIX + e);
84
+ var split = this.getSplit(name);
85
+ if (!split)
101
86
  return false;
102
- }
87
+ this.storage.removeItem(this.keys.buildSplitKey(name));
88
+ this._decrementCounts(split);
89
+ this.removeFromFlagSets(split.name, split.sets);
90
+ return true;
103
91
  };
104
92
  SplitsCacheInLocal.prototype.getSplit = function (name) {
105
93
  var item = this.storage.getItem(this.keys.buildSplitKey(name));
@@ -171,6 +159,8 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
171
159
  var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
172
160
  var flagSetFromStorage = _this.storage.getItem(flagSetKey);
173
161
  var flagSetCache = new Set(flagSetFromStorage ? JSON.parse(flagSetFromStorage) : []);
162
+ if (flagSetCache.has(featureFlag.name))
163
+ return;
174
164
  flagSetCache.add(featureFlag.name);
175
165
  _this.storage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
176
166
  });
@@ -13,9 +13,10 @@ var RBSegmentsCacheInMemory = /** @class */ (function () {
13
13
  };
14
14
  RBSegmentsCacheInMemory.prototype.update = function (toAdd, toRemove, changeNumber) {
15
15
  var _this = this;
16
- this.changeNumber = changeNumber;
17
16
  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;
17
+ updated = toRemove.map(function (toRemove) { return _this.remove(toRemove.name); }).some(function (result) { return result; }) || updated;
18
+ this.changeNumber = changeNumber;
19
+ return updated;
19
20
  };
20
21
  RBSegmentsCacheInMemory.prototype.add = function (rbSegment) {
21
22
  var name = rbSegment.name;
@@ -1,5 +1,5 @@
1
1
  import { isNaNNumber } from '../../utils/lang';
2
- import { LOG_PREFIX } from '../inLocalStorage/constants';
2
+ import { LOG_PREFIX } from './constants';
3
3
  var SegmentsCacheInRedis = /** @class */ (function () {
4
4
  function SegmentsCacheInRedis(log, keys, redis) {
5
5
  this.log = log;
@@ -5,5 +5,5 @@ import { segmentChangesUpdaterFactory } from '../updaters/segmentChangesUpdater'
5
5
  * Creates a sync task that periodically executes a `segmentChangesUpdater` task
6
6
  */
7
7
  export function segmentsSyncTaskFactory(fetchSegmentChanges, storage, readiness, settings) {
8
- return syncTaskFactory(settings.log, segmentChangesUpdaterFactory(settings.log, segmentChangesFetcherFactory(fetchSegmentChanges), storage.segments, readiness), settings.scheduler.segmentsRefreshRate, 'segmentChangesUpdater');
8
+ return syncTaskFactory(settings.log, segmentChangesUpdaterFactory(settings.log, segmentChangesFetcherFactory(fetchSegmentChanges), storage.segments, readiness, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady), settings.scheduler.segmentsRefreshRate, 'segmentChangesUpdater');
9
9
  }
@@ -45,9 +45,9 @@ export function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmen
45
45
  new Promise(function (res) { updateSegments(segmentsData); res(true); }) :
46
46
  // If not provided, fetch mySegments
47
47
  mySegmentsFetcher(matchingKey, noCache, till, _promiseDecorator).then(function (segments) {
48
- // Only when we have downloaded segments completely, we should not keep retrying anymore
49
- startingUp = false;
50
48
  updateSegments(segments);
49
+ // Only when we have downloaded and stored segments completely, we should not keep retrying anymore
50
+ startingUp = false;
51
51
  return true;
52
52
  });
53
53
  return updaterPromise.catch(function (error) {
@@ -1,5 +1,6 @@
1
1
  import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
2
2
  import { LOG_PREFIX_INSTANTIATION, LOG_PREFIX_SYNC_SEGMENTS } from '../../../logger/constants';
3
+ import { timeout } from '../../../utils/promise/timeout';
3
4
  /**
4
5
  * Factory of SegmentChanges updater, a task that:
5
6
  * - fetches segment changes using `segmentChangesFetcher`
@@ -11,22 +12,33 @@ import { LOG_PREFIX_INSTANTIATION, LOG_PREFIX_SYNC_SEGMENTS } from '../../../log
11
12
  * @param segments - segments storage, with sync or async methods
12
13
  * @param readiness - optional readiness manager. Not required for synchronizer or producer mode.
13
14
  */
14
- export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, readiness) {
15
+ export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, readiness, requestTimeoutBeforeReady, retriesOnFailureBeforeReady) {
15
16
  var readyOnAlreadyExistentState = true;
16
- function updateSegment(segmentName, noCache, till, fetchOnlyNew) {
17
+ function _promiseDecorator(promise) {
18
+ if (readyOnAlreadyExistentState && requestTimeoutBeforeReady)
19
+ promise = timeout(requestTimeoutBeforeReady, promise);
20
+ return promise;
21
+ }
22
+ function updateSegment(segmentName, noCache, till, fetchOnlyNew, retries) {
17
23
  log.debug(LOG_PREFIX_SYNC_SEGMENTS + "Processing segment " + segmentName);
18
24
  var sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
19
25
  return sincePromise.then(function (since) {
20
26
  // if fetchOnlyNew flag, avoid processing already fetched segments
21
27
  return fetchOnlyNew && since !== undefined ?
22
28
  false :
23
- segmentChangesFetcher(since || -1, segmentName, noCache, till).then(function (changes) {
29
+ segmentChangesFetcher(since || -1, segmentName, noCache, till, _promiseDecorator).then(function (changes) {
24
30
  return Promise.all(changes.map(function (x) {
25
31
  log.debug(LOG_PREFIX_SYNC_SEGMENTS + "Processing " + segmentName + " with till = " + x.till + ". Added: " + x.added.length + ". Removed: " + x.removed.length);
26
32
  return segments.update(segmentName, x.added, x.removed, x.till);
27
33
  })).then(function (updates) {
28
34
  return updates.some(function (update) { return update; });
29
35
  });
36
+ }).catch(function (error) {
37
+ if (retries) {
38
+ log.warn(LOG_PREFIX_SYNC_SEGMENTS + "Retrying fetch of segment " + segmentName + " (attempt #" + retries + "). Reason: " + error);
39
+ return updateSegment(segmentName, noCache, till, fetchOnlyNew, retries - 1);
40
+ }
41
+ throw error;
30
42
  });
31
43
  });
32
44
  }
@@ -46,8 +58,7 @@ export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segment
46
58
  // If not a segment name provided, read list of available segments names to be updated.
47
59
  var segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
48
60
  return segmentsPromise.then(function (segmentNames) {
49
- // Async fetchers
50
- var updaters = segmentNames.map(function (segmentName) { return updateSegment(segmentName, noCache, till, fetchOnlyNew); });
61
+ var updaters = segmentNames.map(function (segmentName) { return updateSegment(segmentName, noCache, till, fetchOnlyNew, readyOnAlreadyExistentState ? retriesOnFailureBeforeReady : 0); });
51
62
  return Promise.all(updaters).then(function (shouldUpdateFlags) {
52
63
  // if at least one segment fetch succeeded, mark segments ready
53
64
  if (shouldUpdateFlags.some(function (update) { return update; }) || readyOnAlreadyExistentState) {
@@ -130,7 +130,6 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, sp
130
130
  { rbs: { d: [instantUpdate.payload], t: instantUpdate.changeNumber } } :
131
131
  splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator))
132
132
  .then(function (splitChanges) {
133
- startingUp = false;
134
133
  var usedSegments = new Set();
135
134
  var ffUpdate = false;
136
135
  if (splitChanges.ff) {
@@ -151,6 +150,7 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, sp
151
150
  var ffChanged = _a[0], rbsChanged = _a[1];
152
151
  if (storage.save)
153
152
  storage.save();
153
+ startingUp = false;
154
154
  if (splitsEventEmitter) {
155
155
  // To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
156
156
  return Promise.resolve(!splitsEventEmitter.splitsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
@@ -166,14 +166,14 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, sp
166
166
  });
167
167
  })
168
168
  .catch(function (error) {
169
- log.warn(SYNC_SPLITS_FETCH_FAILS, [error]);
170
169
  if (startingUp && retriesOnFailureBeforeReady > retry) {
171
170
  retry += 1;
172
- log.info(SYNC_SPLITS_FETCH_RETRY, [retry, error]);
171
+ log.warn(SYNC_SPLITS_FETCH_RETRY, [retry, error]);
173
172
  return _splitChangesUpdater(sinces, retry);
174
173
  }
175
174
  else {
176
175
  startingUp = false;
176
+ log.warn(SYNC_SPLITS_FETCH_FAILS, [error]);
177
177
  }
178
178
  return false;
179
179
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "2.8.0",
3
+ "version": "2.8.1-rc.0",
4
4
  "description": "Split JavaScript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -49,12 +49,10 @@ export abstract class AbstractMySegmentsCacheSync implements ISegmentsCacheSync
49
49
  * For client-side synchronizer: it resets or updates the cache.
50
50
  */
51
51
  resetSegments(segmentsData: MySegmentsData | IMySegmentsResponse): boolean {
52
- this.setChangeNumber(segmentsData.cn);
53
-
52
+ let isDiff = false;
54
53
  const { added, removed } = segmentsData as MySegmentsData;
55
54
 
56
55
  if (added && removed) {
57
- let isDiff = false;
58
56
 
59
57
  added.forEach(segment => {
60
58
  isDiff = this.addSegment(segment) || isDiff;
@@ -63,32 +61,40 @@ export abstract class AbstractMySegmentsCacheSync implements ISegmentsCacheSync
63
61
  removed.forEach(segment => {
64
62
  isDiff = this.removeSegment(segment) || isDiff;
65
63
  });
64
+ } else {
66
65
 
67
- return isDiff;
68
- }
66
+ const names = ((segmentsData as IMySegmentsResponse).k || []).map(s => s.n).sort();
67
+ const storedSegmentKeys = this.getRegisteredSegments().sort();
69
68
 
70
- const names = ((segmentsData as IMySegmentsResponse).k || []).map(s => s.n).sort();
71
- const storedSegmentKeys = this.getRegisteredSegments().sort();
69
+ // Extreme fast => everything is empty
70
+ if (!names.length && !storedSegmentKeys.length) {
71
+ isDiff = false;
72
+ } else {
72
73
 
73
- // Extreme fast => everything is empty
74
- if (!names.length && !storedSegmentKeys.length) return false;
74
+ let index = 0;
75
75
 
76
- let index = 0;
76
+ while (index < names.length && index < storedSegmentKeys.length && names[index] === storedSegmentKeys[index]) index++;
77
77
 
78
- while (index < names.length && index < storedSegmentKeys.length && names[index] === storedSegmentKeys[index]) index++;
78
+ // Quick path => no changes
79
+ if (index === names.length && index === storedSegmentKeys.length) {
80
+ isDiff = false;
81
+ } else {
79
82
 
80
- // Quick path => no changes
81
- if (index === names.length && index === storedSegmentKeys.length) return false;
83
+ // Slowest path => add and/or remove segments
84
+ for (let removeIndex = index; removeIndex < storedSegmentKeys.length; removeIndex++) {
85
+ this.removeSegment(storedSegmentKeys[removeIndex]);
86
+ }
82
87
 
83
- // Slowest path => add and/or remove segments
84
- for (let removeIndex = index; removeIndex < storedSegmentKeys.length; removeIndex++) {
85
- this.removeSegment(storedSegmentKeys[removeIndex]);
86
- }
88
+ for (let addIndex = index; addIndex < names.length; addIndex++) {
89
+ this.addSegment(names[addIndex]);
90
+ }
87
91
 
88
- for (let addIndex = index; addIndex < names.length; addIndex++) {
89
- this.addSegment(names[addIndex]);
92
+ isDiff = true;
93
+ }
94
+ }
90
95
  }
91
96
 
92
- return true;
97
+ this.setChangeNumber(segmentsData.cn);
98
+ return isDiff;
93
99
  }
94
100
  }
@@ -14,9 +14,10 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
14
14
  protected abstract setChangeNumber(changeNumber: number): boolean | void
15
15
 
16
16
  update(toAdd: ISplit[], toRemove: ISplit[], changeNumber: number): boolean {
17
+ let updated = toAdd.map(addedFF => this.addSplit(addedFF)).some(result => result);
18
+ updated = toRemove.map(removedFF => this.removeSplit(removedFF.name)).some(result => result) || updated;
17
19
  this.setChangeNumber(changeNumber);
18
- const updated = toAdd.map(addedFF => this.addSplit(addedFF)).some(result => result);
19
- return toRemove.map(removedFF => this.removeSplit(removedFF.name)).some(result => result) || updated;
20
+ return updated;
20
21
  }
21
22
 
22
23
  abstract getSplit(name: string): ISplit | null
@@ -2,7 +2,7 @@ import { ILogger } from '../../logger/types';
2
2
  import { isNaNNumber } from '../../utils/lang';
3
3
  import { AbstractMySegmentsCacheSync } from '../AbstractMySegmentsCacheSync';
4
4
  import type { MySegmentsKeyBuilder } from '../KeyBuilderCS';
5
- import { LOG_PREFIX, DEFINED } from './constants';
5
+ import { DEFINED } from './constants';
6
6
  import { StorageAdapter } from '../types';
7
7
 
8
8
  export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
@@ -16,33 +16,22 @@ export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
16
16
  this.log = log;
17
17
  this.keys = keys;
18
18
  this.storage = storage;
19
- // There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
20
19
  }
21
20
 
22
21
  protected addSegment(name: string): boolean {
23
22
  const segmentKey = this.keys.buildSegmentNameKey(name);
24
23
 
25
- try {
26
- if (this.storage.getItem(segmentKey) === DEFINED) return false;
27
- this.storage.setItem(segmentKey, DEFINED);
28
- return true;
29
- } catch (e) {
30
- this.log.error(LOG_PREFIX + e);
31
- return false;
32
- }
24
+ if (this.storage.getItem(segmentKey) === DEFINED) return false;
25
+ this.storage.setItem(segmentKey, DEFINED);
26
+ return true;
33
27
  }
34
28
 
35
29
  protected removeSegment(name: string): boolean {
36
30
  const segmentKey = this.keys.buildSegmentNameKey(name);
37
31
 
38
- try {
39
- if (this.storage.getItem(segmentKey) !== DEFINED) return false;
40
- this.storage.removeItem(segmentKey);
41
- return true;
42
- } catch (e) {
43
- this.log.error(LOG_PREFIX + e);
44
- return false;
45
- }
32
+ if (this.storage.getItem(segmentKey) !== DEFINED) return false;
33
+ this.storage.removeItem(segmentKey);
34
+ return true;
46
35
  }
47
36
 
48
37
  isInSegment(name: string): boolean {
@@ -63,12 +52,8 @@ export class MySegmentsCacheInLocal extends AbstractMySegmentsCacheSync {
63
52
  }
64
53
 
65
54
  protected setChangeNumber(changeNumber?: number) {
66
- try {
67
- if (changeNumber) this.storage.setItem(this.keys.buildTillKey(), changeNumber + '');
68
- else this.storage.removeItem(this.keys.buildTillKey());
69
- } catch (e) {
70
- this.log.error(e);
71
- }
55
+ if (changeNumber) this.storage.setItem(this.keys.buildTillKey(), changeNumber + '');
56
+ else this.storage.removeItem(this.keys.buildTillKey());
72
57
  }
73
58
 
74
59
  getChangeNumber() {
@@ -26,9 +26,10 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
26
26
  }
27
27
 
28
28
  update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): boolean {
29
+ let updated = toAdd.map(toAdd => this.add(toAdd)).some(result => result);
30
+ updated = toRemove.map(toRemove => this.remove(toRemove.name)).some(result => result) || updated;
29
31
  this.setChangeNumber(changeNumber);
30
- const updated = toAdd.map(toAdd => this.add(toAdd)).some(result => result);
31
- return toRemove.map(toRemove => this.remove(toRemove.name)).some(result => result) || updated;
32
+ return updated;
32
33
  }
33
34
 
34
35
  private setChangeNumber(changeNumber: number) {
@@ -48,40 +49,30 @@ export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
48
49
  }
49
50
 
50
51
  private add(rbSegment: IRBSegment): boolean {
51
- try {
52
- const name = rbSegment.name;
53
- const rbSegmentKey = this.keys.buildRBSegmentKey(name);
54
- const rbSegmentFromStorage = this.storage.getItem(rbSegmentKey);
55
- const previous = rbSegmentFromStorage ? JSON.parse(rbSegmentFromStorage) : null;
52
+ const name = rbSegment.name;
53
+ const rbSegmentKey = this.keys.buildRBSegmentKey(name);
54
+ const rbSegmentFromStorage = this.storage.getItem(rbSegmentKey);
55
+ const previous = rbSegmentFromStorage ? JSON.parse(rbSegmentFromStorage) : null;
56
56
 
57
- this.storage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
57
+ this.storage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
58
58
 
59
- let usesSegmentsDiff = 0;
60
- if (previous && usesSegments(previous)) usesSegmentsDiff--;
61
- if (usesSegments(rbSegment)) usesSegmentsDiff++;
62
- if (usesSegmentsDiff !== 0) this.updateSegmentCount(usesSegmentsDiff);
59
+ let usesSegmentsDiff = 0;
60
+ if (previous && usesSegments(previous)) usesSegmentsDiff--;
61
+ if (usesSegments(rbSegment)) usesSegmentsDiff++;
62
+ if (usesSegmentsDiff !== 0) this.updateSegmentCount(usesSegmentsDiff);
63
63
 
64
- return true;
65
- } catch (e) {
66
- this.log.error(LOG_PREFIX + e);
67
- return false;
68
- }
64
+ return true;
69
65
  }
70
66
 
71
67
  private remove(name: string): boolean {
72
- try {
73
- const rbSegment = this.get(name);
74
- if (!rbSegment) return false;
68
+ const rbSegment = this.get(name);
69
+ if (!rbSegment) return false;
75
70
 
76
- this.storage.removeItem(this.keys.buildRBSegmentKey(name));
71
+ this.storage.removeItem(this.keys.buildRBSegmentKey(name));
77
72
 
78
- if (usesSegments(rbSegment)) this.updateSegmentCount(-1);
73
+ if (usesSegments(rbSegment)) this.updateSegmentCount(-1);
79
74
 
80
- return true;
81
- } catch (e) {
82
- this.log.error(LOG_PREFIX + e);
83
- return false;
84
- }
75
+ return true;
85
76
  }
86
77
 
87
78
  private getNames(): string[] {
@@ -80,44 +80,34 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
80
80
  }
81
81
 
82
82
  addSplit(split: ISplit) {
83
- try {
84
- const name = split.name;
85
- const splitKey = this.keys.buildSplitKey(name);
86
- const splitFromStorage = this.storage.getItem(splitKey);
87
- const previousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : null;
88
-
89
- if (previousSplit) {
90
- this._decrementCounts(previousSplit);
91
- this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
92
- }
83
+ const name = split.name;
84
+ const splitKey = this.keys.buildSplitKey(name);
85
+ const splitFromStorage = this.storage.getItem(splitKey);
86
+ const previousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : null;
87
+
88
+ if (previousSplit) {
89
+ this._decrementCounts(previousSplit);
90
+ this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
91
+ }
93
92
 
94
- this.storage.setItem(splitKey, JSON.stringify(split));
93
+ this.storage.setItem(splitKey, JSON.stringify(split));
95
94
 
96
- this._incrementCounts(split);
97
- this.addToFlagSets(split);
95
+ this._incrementCounts(split);
96
+ this.addToFlagSets(split);
98
97
 
99
- return true;
100
- } catch (e) {
101
- this.log.error(LOG_PREFIX + e);
102
- return false;
103
- }
98
+ return true;
104
99
  }
105
100
 
106
101
  removeSplit(name: string): boolean {
107
- try {
108
- const split = this.getSplit(name);
109
- if (!split) return false;
102
+ const split = this.getSplit(name);
103
+ if (!split) return false;
110
104
 
111
- this.storage.removeItem(this.keys.buildSplitKey(name));
105
+ this.storage.removeItem(this.keys.buildSplitKey(name));
112
106
 
113
- this._decrementCounts(split);
114
- this.removeFromFlagSets(split.name, split.sets);
107
+ this._decrementCounts(split);
108
+ this.removeFromFlagSets(split.name, split.sets);
115
109
 
116
- return true;
117
- } catch (e) {
118
- this.log.error(LOG_PREFIX + e);
119
- return false;
120
- }
110
+ return true;
121
111
  }
122
112
 
123
113
  getSplit(name: string): ISplit | null {
@@ -206,6 +196,9 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
206
196
  const flagSetFromStorage = this.storage.getItem(flagSetKey);
207
197
 
208
198
  const flagSetCache = new Set(flagSetFromStorage ? JSON.parse(flagSetFromStorage) : []);
199
+
200
+ if (flagSetCache.has(featureFlag.name)) return;
201
+
209
202
  flagSetCache.add(featureFlag.name);
210
203
 
211
204
  this.storage.setItem(flagSetKey, JSON.stringify(setToArray(flagSetCache)));
@@ -16,9 +16,10 @@ export class RBSegmentsCacheInMemory implements IRBSegmentsCacheSync {
16
16
  }
17
17
 
18
18
  update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): boolean {
19
+ let updated = toAdd.map(toAdd => this.add(toAdd)).some(result => result);
20
+ updated = toRemove.map(toRemove => this.remove(toRemove.name)).some(result => result) || updated;
19
21
  this.changeNumber = changeNumber;
20
- const updated = toAdd.map(toAdd => this.add(toAdd)).some(result => result);
21
- return toRemove.map(toRemove => this.remove(toRemove.name)).some(result => result) || updated;
22
+ return updated;
22
23
  }
23
24
 
24
25
  private add(rbSegment: IRBSegment): boolean {
@@ -1,6 +1,6 @@
1
1
  import { ILogger } from '../../logger/types';
2
2
  import { isNaNNumber } from '../../utils/lang';
3
- import { LOG_PREFIX } from '../inLocalStorage/constants';
3
+ import { LOG_PREFIX } from './constants';
4
4
  import { KeyBuilderSS } from '../KeyBuilderSS';
5
5
  import { ISegmentsCacheAsync } from '../types';
6
6
  import type { RedisAdapter } from './RedisAdapter';
@@ -23,6 +23,8 @@ export function segmentsSyncTaskFactory(
23
23
  segmentChangesFetcherFactory(fetchSegmentChanges),
24
24
  storage.segments,
25
25
  readiness,
26
+ settings.startup.requestTimeoutBeforeReady,
27
+ settings.startup.retriesOnFailureBeforeReady,
26
28
  ),
27
29
  settings.scheduler.segmentsRefreshRate,
28
30
  'segmentChangesUpdater'
@@ -66,10 +66,10 @@ export function mySegmentsUpdaterFactory(
66
66
  new Promise((res) => { updateSegments(segmentsData); res(true); }) :
67
67
  // If not provided, fetch mySegments
68
68
  mySegmentsFetcher(matchingKey, noCache, till, _promiseDecorator).then(segments => {
69
- // Only when we have downloaded segments completely, we should not keep retrying anymore
70
- startingUp = false;
71
-
72
69
  updateSegments(segments);
70
+
71
+ // Only when we have downloaded and stored segments completely, we should not keep retrying anymore
72
+ startingUp = false;
73
73
  return true;
74
74
  });
75
75