@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.
- package/CHANGES.txt +4 -0
- package/cjs/storages/AbstractMySegmentsCacheSync.js +31 -23
- package/cjs/storages/AbstractSplitsCacheSync.js +3 -2
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +10 -28
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +22 -33
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +19 -29
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +3 -2
- package/cjs/storages/inRedis/SegmentsCacheInRedis.js +1 -1
- package/cjs/sync/polling/syncTasks/segmentsSyncTask.js +1 -1
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +16 -5
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +3 -3
- package/esm/storages/AbstractMySegmentsCacheSync.js +31 -23
- package/esm/storages/AbstractSplitsCacheSync.js +3 -2
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +11 -29
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +22 -33
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +19 -29
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +3 -2
- package/esm/storages/inRedis/SegmentsCacheInRedis.js +1 -1
- package/esm/sync/polling/syncTasks/segmentsSyncTask.js +1 -1
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +16 -5
- package/esm/sync/polling/updaters/splitChangesUpdater.js +3 -3
- package/package.json +1 -1
- package/src/storages/AbstractMySegmentsCacheSync.ts +26 -20
- package/src/storages/AbstractSplitsCacheSync.ts +3 -2
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +9 -24
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +18 -27
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +22 -29
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +3 -2
- package/src/storages/inRedis/SegmentsCacheInRedis.ts +1 -1
- package/src/sync/polling/syncTasks/segmentsSyncTask.ts +2 -0
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +3 -3
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +17 -4
- package/src/sync/polling/updaters/splitChangesUpdater.ts +6 -7
- package/types/splitio.d.ts +0 -2
package/CHANGES.txt
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
2.9.0 (November 26, 2025)
|
|
2
|
+
- Updated the SDK’s initial synchronization in Node.js (server-side) to use the `startup.requestTimeoutBeforeReady` and `startup.retriesOnFailureBeforeReady` options to control the timeout and retry behavior of segment requests.
|
|
3
|
+
- Updated the order of storage operations to prevent inconsistent states when using the `LOCALSTORAGE` storage type and the browser’s `localStorage` fails due to quota limits.
|
|
4
|
+
|
|
1
5
|
2.8.0 (October 30, 2025)
|
|
2
6
|
- Added new configuration for Fallback Treatments, which allows setting a treatment value and optional config to be returned in place of "control", either globally or by flag. Read more in our docs.
|
|
3
7
|
- Added `client.getStatus()` method to retrieve the client readiness status properties (`isReady`, `isReadyFromCache`, etc).
|
|
@@ -23,37 +23,45 @@ var AbstractMySegmentsCacheSync = /** @class */ (function () {
|
|
|
23
23
|
*/
|
|
24
24
|
AbstractMySegmentsCacheSync.prototype.resetSegments = function (segmentsData) {
|
|
25
25
|
var _this = this;
|
|
26
|
-
|
|
26
|
+
var isDiff = false;
|
|
27
27
|
var _a = segmentsData, added = _a.added, removed = _a.removed;
|
|
28
28
|
if (added && removed) {
|
|
29
|
-
var isDiff_1 = false;
|
|
30
29
|
added.forEach(function (segment) {
|
|
31
|
-
|
|
30
|
+
isDiff = _this.addSegment(segment) || isDiff;
|
|
32
31
|
});
|
|
33
32
|
removed.forEach(function (segment) {
|
|
34
|
-
|
|
33
|
+
isDiff = _this.removeSegment(segment) || isDiff;
|
|
35
34
|
});
|
|
36
|
-
return isDiff_1;
|
|
37
|
-
}
|
|
38
|
-
var names = (segmentsData.k || []).map(function (s) { return s.n; }).sort();
|
|
39
|
-
var storedSegmentKeys = this.getRegisteredSegments().sort();
|
|
40
|
-
// Extreme fast => everything is empty
|
|
41
|
-
if (!names.length && !storedSegmentKeys.length)
|
|
42
|
-
return false;
|
|
43
|
-
var index = 0;
|
|
44
|
-
while (index < names.length && index < storedSegmentKeys.length && names[index] === storedSegmentKeys[index])
|
|
45
|
-
index++;
|
|
46
|
-
// Quick path => no changes
|
|
47
|
-
if (index === names.length && index === storedSegmentKeys.length)
|
|
48
|
-
return false;
|
|
49
|
-
// Slowest path => add and/or remove segments
|
|
50
|
-
for (var removeIndex = index; removeIndex < storedSegmentKeys.length; removeIndex++) {
|
|
51
|
-
this.removeSegment(storedSegmentKeys[removeIndex]);
|
|
52
35
|
}
|
|
53
|
-
|
|
54
|
-
|
|
36
|
+
else {
|
|
37
|
+
var names = (segmentsData.k || []).map(function (s) { return s.n; }).sort();
|
|
38
|
+
var storedSegmentKeys = this.getRegisteredSegments().sort();
|
|
39
|
+
// Extreme fast => everything is empty
|
|
40
|
+
if (!names.length && !storedSegmentKeys.length) {
|
|
41
|
+
isDiff = false;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
var index = 0;
|
|
45
|
+
while (index < names.length && index < storedSegmentKeys.length && names[index] === storedSegmentKeys[index])
|
|
46
|
+
index++;
|
|
47
|
+
// Quick path => no changes
|
|
48
|
+
if (index === names.length && index === storedSegmentKeys.length) {
|
|
49
|
+
isDiff = false;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// Slowest path => add and/or remove segments
|
|
53
|
+
for (var removeIndex = index; removeIndex < storedSegmentKeys.length; removeIndex++) {
|
|
54
|
+
this.removeSegment(storedSegmentKeys[removeIndex]);
|
|
55
|
+
}
|
|
56
|
+
for (var addIndex = index; addIndex < names.length; addIndex++) {
|
|
57
|
+
this.addSegment(names[addIndex]);
|
|
58
|
+
}
|
|
59
|
+
isDiff = true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
55
62
|
}
|
|
56
|
-
|
|
63
|
+
this.setChangeNumber(segmentsData.cn);
|
|
64
|
+
return isDiff;
|
|
57
65
|
};
|
|
58
66
|
return AbstractMySegmentsCacheSync;
|
|
59
67
|
}());
|
|
@@ -12,9 +12,10 @@ var AbstractSplitsCacheSync = /** @class */ (function () {
|
|
|
12
12
|
}
|
|
13
13
|
AbstractSplitsCacheSync.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
14
14
|
var _this = this;
|
|
15
|
-
this.setChangeNumber(changeNumber);
|
|
16
15
|
var updated = toAdd.map(function (addedFF) { return _this.addSplit(addedFF); }).some(function (result) { return result; });
|
|
17
|
-
|
|
16
|
+
updated = toRemove.map(function (removedFF) { return _this.removeSplit(removedFF.name); }).some(function (result) { return result; }) || updated;
|
|
17
|
+
this.setChangeNumber(changeNumber);
|
|
18
|
+
return updated;
|
|
18
19
|
};
|
|
19
20
|
AbstractSplitsCacheSync.prototype.getSplits = function (names) {
|
|
20
21
|
var _this = this;
|
|
@@ -13,33 +13,20 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
13
13
|
_this.keys = keys;
|
|
14
14
|
_this.storage = storage;
|
|
15
15
|
return _this;
|
|
16
|
-
// There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
|
|
17
16
|
}
|
|
18
17
|
MySegmentsCacheInLocal.prototype.addSegment = function (name) {
|
|
19
18
|
var segmentKey = this.keys.buildSegmentNameKey(name);
|
|
20
|
-
|
|
21
|
-
if (this.storage.getItem(segmentKey) === constants_1.DEFINED)
|
|
22
|
-
return false;
|
|
23
|
-
this.storage.setItem(segmentKey, constants_1.DEFINED);
|
|
24
|
-
return true;
|
|
25
|
-
}
|
|
26
|
-
catch (e) {
|
|
27
|
-
this.log.error(constants_1.LOG_PREFIX + e);
|
|
19
|
+
if (this.storage.getItem(segmentKey) === constants_1.DEFINED)
|
|
28
20
|
return false;
|
|
29
|
-
|
|
21
|
+
this.storage.setItem(segmentKey, constants_1.DEFINED);
|
|
22
|
+
return true;
|
|
30
23
|
};
|
|
31
24
|
MySegmentsCacheInLocal.prototype.removeSegment = function (name) {
|
|
32
25
|
var segmentKey = this.keys.buildSegmentNameKey(name);
|
|
33
|
-
|
|
34
|
-
if (this.storage.getItem(segmentKey) !== constants_1.DEFINED)
|
|
35
|
-
return false;
|
|
36
|
-
this.storage.removeItem(segmentKey);
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
catch (e) {
|
|
40
|
-
this.log.error(constants_1.LOG_PREFIX + e);
|
|
26
|
+
if (this.storage.getItem(segmentKey) !== constants_1.DEFINED)
|
|
41
27
|
return false;
|
|
42
|
-
|
|
28
|
+
this.storage.removeItem(segmentKey);
|
|
29
|
+
return true;
|
|
43
30
|
};
|
|
44
31
|
MySegmentsCacheInLocal.prototype.isInSegment = function (name) {
|
|
45
32
|
return this.storage.getItem(this.keys.buildSegmentNameKey(name)) === constants_1.DEFINED;
|
|
@@ -57,15 +44,10 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
57
44
|
return 1;
|
|
58
45
|
};
|
|
59
46
|
MySegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
this.storage.removeItem(this.keys.buildTillKey());
|
|
65
|
-
}
|
|
66
|
-
catch (e) {
|
|
67
|
-
this.log.error(e);
|
|
68
|
-
}
|
|
47
|
+
if (changeNumber)
|
|
48
|
+
this.storage.setItem(this.keys.buildTillKey(), changeNumber + '');
|
|
49
|
+
else
|
|
50
|
+
this.storage.removeItem(this.keys.buildTillKey());
|
|
69
51
|
};
|
|
70
52
|
MySegmentsCacheInLocal.prototype.getChangeNumber = function () {
|
|
71
53
|
var n = -1;
|
|
@@ -18,9 +18,10 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
18
18
|
};
|
|
19
19
|
RBSegmentsCacheInLocal.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
20
20
|
var _this = this;
|
|
21
|
-
this.setChangeNumber(changeNumber);
|
|
22
21
|
var updated = toAdd.map(function (toAdd) { return _this.add(toAdd); }).some(function (result) { return result; });
|
|
23
|
-
|
|
22
|
+
updated = toRemove.map(function (toRemove) { return _this.remove(toRemove.name); }).some(function (result) { return result; }) || updated;
|
|
23
|
+
this.setChangeNumber(changeNumber);
|
|
24
|
+
return updated;
|
|
24
25
|
};
|
|
25
26
|
RBSegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
26
27
|
try {
|
|
@@ -40,40 +41,28 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
|
|
|
40
41
|
this.storage.removeItem(segmentsCountKey);
|
|
41
42
|
};
|
|
42
43
|
RBSegmentsCacheInLocal.prototype.add = function (rbSegment) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
catch (e) {
|
|
59
|
-
this.log.error(constants_1.LOG_PREFIX + e);
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
44
|
+
var name = rbSegment.name;
|
|
45
|
+
var rbSegmentKey = this.keys.buildRBSegmentKey(name);
|
|
46
|
+
var rbSegmentFromStorage = this.storage.getItem(rbSegmentKey);
|
|
47
|
+
var previous = rbSegmentFromStorage ? JSON.parse(rbSegmentFromStorage) : null;
|
|
48
|
+
this.storage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
|
|
49
|
+
var usesSegmentsDiff = 0;
|
|
50
|
+
if (previous && (0, AbstractSplitsCacheSync_1.usesSegments)(previous))
|
|
51
|
+
usesSegmentsDiff--;
|
|
52
|
+
if ((0, AbstractSplitsCacheSync_1.usesSegments)(rbSegment))
|
|
53
|
+
usesSegmentsDiff++;
|
|
54
|
+
if (usesSegmentsDiff !== 0)
|
|
55
|
+
this.updateSegmentCount(usesSegmentsDiff);
|
|
56
|
+
return true;
|
|
62
57
|
};
|
|
63
58
|
RBSegmentsCacheInLocal.prototype.remove = function (name) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (!rbSegment)
|
|
67
|
-
return false;
|
|
68
|
-
this.storage.removeItem(this.keys.buildRBSegmentKey(name));
|
|
69
|
-
if ((0, AbstractSplitsCacheSync_1.usesSegments)(rbSegment))
|
|
70
|
-
this.updateSegmentCount(-1);
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
catch (e) {
|
|
74
|
-
this.log.error(constants_1.LOG_PREFIX + e);
|
|
59
|
+
var rbSegment = this.get(name);
|
|
60
|
+
if (!rbSegment)
|
|
75
61
|
return false;
|
|
76
|
-
|
|
62
|
+
this.storage.removeItem(this.keys.buildRBSegmentKey(name));
|
|
63
|
+
if ((0, AbstractSplitsCacheSync_1.usesSegments)(rbSegment))
|
|
64
|
+
this.updateSegmentCount(-1);
|
|
65
|
+
return true;
|
|
77
66
|
};
|
|
78
67
|
RBSegmentsCacheInLocal.prototype.getNames = function () {
|
|
79
68
|
var len = this.storage.length;
|
|
@@ -70,39 +70,27 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
70
70
|
this.hasSync = false;
|
|
71
71
|
};
|
|
72
72
|
SplitsCacheInLocal.prototype.addSplit = function (split) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
81
|
-
}
|
|
82
|
-
this.storage.setItem(splitKey, JSON.stringify(split));
|
|
83
|
-
this._incrementCounts(split);
|
|
84
|
-
this.addToFlagSets(split);
|
|
85
|
-
return true;
|
|
86
|
-
}
|
|
87
|
-
catch (e) {
|
|
88
|
-
this.log.error(constants_1.LOG_PREFIX + e);
|
|
89
|
-
return false;
|
|
73
|
+
var name = split.name;
|
|
74
|
+
var splitKey = this.keys.buildSplitKey(name);
|
|
75
|
+
var splitFromStorage = this.storage.getItem(splitKey);
|
|
76
|
+
var previousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : null;
|
|
77
|
+
if (previousSplit) {
|
|
78
|
+
this._decrementCounts(previousSplit);
|
|
79
|
+
this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
|
|
90
80
|
}
|
|
81
|
+
this.storage.setItem(splitKey, JSON.stringify(split));
|
|
82
|
+
this._incrementCounts(split);
|
|
83
|
+
this.addToFlagSets(split);
|
|
84
|
+
return true;
|
|
91
85
|
};
|
|
92
86
|
SplitsCacheInLocal.prototype.removeSplit = function (name) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (!split)
|
|
96
|
-
return false;
|
|
97
|
-
this.storage.removeItem(this.keys.buildSplitKey(name));
|
|
98
|
-
this._decrementCounts(split);
|
|
99
|
-
this.removeFromFlagSets(split.name, split.sets);
|
|
100
|
-
return true;
|
|
101
|
-
}
|
|
102
|
-
catch (e) {
|
|
103
|
-
this.log.error(constants_1.LOG_PREFIX + e);
|
|
87
|
+
var split = this.getSplit(name);
|
|
88
|
+
if (!split)
|
|
104
89
|
return false;
|
|
105
|
-
|
|
90
|
+
this.storage.removeItem(this.keys.buildSplitKey(name));
|
|
91
|
+
this._decrementCounts(split);
|
|
92
|
+
this.removeFromFlagSets(split.name, split.sets);
|
|
93
|
+
return true;
|
|
106
94
|
};
|
|
107
95
|
SplitsCacheInLocal.prototype.getSplit = function (name) {
|
|
108
96
|
var item = this.storage.getItem(this.keys.buildSplitKey(name));
|
|
@@ -174,6 +162,8 @@ var SplitsCacheInLocal = /** @class */ (function (_super) {
|
|
|
174
162
|
var flagSetKey = _this.keys.buildFlagSetKey(featureFlagSet);
|
|
175
163
|
var flagSetFromStorage = _this.storage.getItem(flagSetKey);
|
|
176
164
|
var flagSetCache = new Set(flagSetFromStorage ? JSON.parse(flagSetFromStorage) : []);
|
|
165
|
+
if (flagSetCache.has(featureFlag.name))
|
|
166
|
+
return;
|
|
177
167
|
flagSetCache.add(featureFlag.name);
|
|
178
168
|
_this.storage.setItem(flagSetKey, JSON.stringify((0, sets_1.setToArray)(flagSetCache)));
|
|
179
169
|
});
|
|
@@ -16,9 +16,10 @@ var RBSegmentsCacheInMemory = /** @class */ (function () {
|
|
|
16
16
|
};
|
|
17
17
|
RBSegmentsCacheInMemory.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
18
18
|
var _this = this;
|
|
19
|
-
this.changeNumber = changeNumber;
|
|
20
19
|
var updated = toAdd.map(function (toAdd) { return _this.add(toAdd); }).some(function (result) { return result; });
|
|
21
|
-
|
|
20
|
+
updated = toRemove.map(function (toRemove) { return _this.remove(toRemove.name); }).some(function (result) { return result; }) || updated;
|
|
21
|
+
this.changeNumber = changeNumber;
|
|
22
|
+
return updated;
|
|
22
23
|
};
|
|
23
24
|
RBSegmentsCacheInMemory.prototype.add = function (rbSegment) {
|
|
24
25
|
var name = rbSegment.name;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SegmentsCacheInRedis = void 0;
|
|
4
4
|
var lang_1 = require("../../utils/lang");
|
|
5
|
-
var constants_1 = require("
|
|
5
|
+
var constants_1 = require("./constants");
|
|
6
6
|
var SegmentsCacheInRedis = /** @class */ (function () {
|
|
7
7
|
function SegmentsCacheInRedis(log, keys, redis) {
|
|
8
8
|
this.log = log;
|
|
@@ -8,6 +8,6 @@ var segmentChangesUpdater_1 = require("../updaters/segmentChangesUpdater");
|
|
|
8
8
|
* Creates a sync task that periodically executes a `segmentChangesUpdater` task
|
|
9
9
|
*/
|
|
10
10
|
function segmentsSyncTaskFactory(fetchSegmentChanges, storage, readiness, settings) {
|
|
11
|
-
return (0, syncTask_1.syncTaskFactory)(settings.log, (0, segmentChangesUpdater_1.segmentChangesUpdaterFactory)(settings.log, (0, segmentChangesFetcher_1.segmentChangesFetcherFactory)(fetchSegmentChanges), storage.segments, readiness), settings.scheduler.segmentsRefreshRate, 'segmentChangesUpdater');
|
|
11
|
+
return (0, syncTask_1.syncTaskFactory)(settings.log, (0, segmentChangesUpdater_1.segmentChangesUpdaterFactory)(settings.log, (0, segmentChangesFetcher_1.segmentChangesFetcherFactory)(fetchSegmentChanges), storage.segments, readiness, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady), settings.scheduler.segmentsRefreshRate, 'segmentChangesUpdater');
|
|
12
12
|
}
|
|
13
13
|
exports.segmentsSyncTaskFactory = segmentsSyncTaskFactory;
|
|
@@ -48,9 +48,9 @@ function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmentsEvent
|
|
|
48
48
|
new Promise(function (res) { updateSegments(segmentsData); res(true); }) :
|
|
49
49
|
// If not provided, fetch mySegments
|
|
50
50
|
mySegmentsFetcher(matchingKey, noCache, till, _promiseDecorator).then(function (segments) {
|
|
51
|
-
// Only when we have downloaded segments completely, we should not keep retrying anymore
|
|
52
|
-
startingUp = false;
|
|
53
51
|
updateSegments(segments);
|
|
52
|
+
// Only when we have downloaded and stored segments completely, we should not keep retrying anymore
|
|
53
|
+
startingUp = false;
|
|
54
54
|
return true;
|
|
55
55
|
});
|
|
56
56
|
return updaterPromise.catch(function (error) {
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.segmentChangesUpdaterFactory = void 0;
|
|
4
4
|
var constants_1 = require("../../../readiness/constants");
|
|
5
5
|
var constants_2 = require("../../../logger/constants");
|
|
6
|
+
var timeout_1 = require("../../../utils/promise/timeout");
|
|
6
7
|
/**
|
|
7
8
|
* Factory of SegmentChanges updater, a task that:
|
|
8
9
|
* - fetches segment changes using `segmentChangesFetcher`
|
|
@@ -14,22 +15,33 @@ var constants_2 = require("../../../logger/constants");
|
|
|
14
15
|
* @param segments - segments storage, with sync or async methods
|
|
15
16
|
* @param readiness - optional readiness manager. Not required for synchronizer or producer mode.
|
|
16
17
|
*/
|
|
17
|
-
function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, readiness) {
|
|
18
|
+
function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, readiness, requestTimeoutBeforeReady, retriesOnFailureBeforeReady) {
|
|
18
19
|
var readyOnAlreadyExistentState = true;
|
|
19
|
-
function
|
|
20
|
+
function _promiseDecorator(promise) {
|
|
21
|
+
if (readyOnAlreadyExistentState && requestTimeoutBeforeReady)
|
|
22
|
+
promise = (0, timeout_1.timeout)(requestTimeoutBeforeReady, promise);
|
|
23
|
+
return promise;
|
|
24
|
+
}
|
|
25
|
+
function updateSegment(segmentName, noCache, till, fetchOnlyNew, retries) {
|
|
20
26
|
log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Processing segment " + segmentName);
|
|
21
27
|
var sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
|
|
22
28
|
return sincePromise.then(function (since) {
|
|
23
29
|
// if fetchOnlyNew flag, avoid processing already fetched segments
|
|
24
30
|
return fetchOnlyNew && since !== undefined ?
|
|
25
31
|
false :
|
|
26
|
-
segmentChangesFetcher(since || -1, segmentName, noCache, till).then(function (changes) {
|
|
32
|
+
segmentChangesFetcher(since || -1, segmentName, noCache, till, _promiseDecorator).then(function (changes) {
|
|
27
33
|
return Promise.all(changes.map(function (x) {
|
|
28
34
|
log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Processing " + segmentName + " with till = " + x.till + ". Added: " + x.added.length + ". Removed: " + x.removed.length);
|
|
29
35
|
return segments.update(segmentName, x.added, x.removed, x.till);
|
|
30
36
|
})).then(function (updates) {
|
|
31
37
|
return updates.some(function (update) { return update; });
|
|
32
38
|
});
|
|
39
|
+
}).catch(function (error) {
|
|
40
|
+
if (retries) {
|
|
41
|
+
log.warn(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Retrying fetch of segment " + segmentName + " (attempt #" + retries + "). Reason: " + error);
|
|
42
|
+
return updateSegment(segmentName, noCache, till, fetchOnlyNew, retries - 1);
|
|
43
|
+
}
|
|
44
|
+
throw error;
|
|
33
45
|
});
|
|
34
46
|
});
|
|
35
47
|
}
|
|
@@ -49,8 +61,7 @@ function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, read
|
|
|
49
61
|
// If not a segment name provided, read list of available segments names to be updated.
|
|
50
62
|
var segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
|
|
51
63
|
return segmentsPromise.then(function (segmentNames) {
|
|
52
|
-
|
|
53
|
-
var updaters = segmentNames.map(function (segmentName) { return updateSegment(segmentName, noCache, till, fetchOnlyNew); });
|
|
64
|
+
var updaters = segmentNames.map(function (segmentName) { return updateSegment(segmentName, noCache, till, fetchOnlyNew, readyOnAlreadyExistentState ? retriesOnFailureBeforeReady : 0); });
|
|
54
65
|
return Promise.all(updaters).then(function (shouldUpdateFlags) {
|
|
55
66
|
// if at least one segment fetch succeeded, mark segments ready
|
|
56
67
|
if (shouldUpdateFlags.some(function (update) { return update; }) || readyOnAlreadyExistentState) {
|
|
@@ -135,7 +135,6 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFilt
|
|
|
135
135
|
{ rbs: { d: [instantUpdate.payload], t: instantUpdate.changeNumber } } :
|
|
136
136
|
splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator))
|
|
137
137
|
.then(function (splitChanges) {
|
|
138
|
-
startingUp = false;
|
|
139
138
|
var usedSegments = new Set();
|
|
140
139
|
var ffUpdate = false;
|
|
141
140
|
if (splitChanges.ff) {
|
|
@@ -156,6 +155,7 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFilt
|
|
|
156
155
|
var ffChanged = _a[0], rbsChanged = _a[1];
|
|
157
156
|
if (storage.save)
|
|
158
157
|
storage.save();
|
|
158
|
+
startingUp = false;
|
|
159
159
|
if (splitsEventEmitter) {
|
|
160
160
|
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
161
161
|
return Promise.resolve(!splitsEventEmitter.splitsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
|
|
@@ -171,14 +171,14 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, storage, splitFilt
|
|
|
171
171
|
});
|
|
172
172
|
})
|
|
173
173
|
.catch(function (error) {
|
|
174
|
-
log.warn(constants_2.SYNC_SPLITS_FETCH_FAILS, [error]);
|
|
175
174
|
if (startingUp && retriesOnFailureBeforeReady > retry) {
|
|
176
175
|
retry += 1;
|
|
177
|
-
log.
|
|
176
|
+
log.warn(constants_2.SYNC_SPLITS_FETCH_RETRY, [retry, error]);
|
|
178
177
|
return _splitChangesUpdater(sinces, retry);
|
|
179
178
|
}
|
|
180
179
|
else {
|
|
181
180
|
startingUp = false;
|
|
181
|
+
log.warn(constants_2.SYNC_SPLITS_FETCH_FAILS, [error]);
|
|
182
182
|
}
|
|
183
183
|
return false;
|
|
184
184
|
});
|
|
@@ -20,37 +20,45 @@ var AbstractMySegmentsCacheSync = /** @class */ (function () {
|
|
|
20
20
|
*/
|
|
21
21
|
AbstractMySegmentsCacheSync.prototype.resetSegments = function (segmentsData) {
|
|
22
22
|
var _this = this;
|
|
23
|
-
|
|
23
|
+
var isDiff = false;
|
|
24
24
|
var _a = segmentsData, added = _a.added, removed = _a.removed;
|
|
25
25
|
if (added && removed) {
|
|
26
|
-
var isDiff_1 = false;
|
|
27
26
|
added.forEach(function (segment) {
|
|
28
|
-
|
|
27
|
+
isDiff = _this.addSegment(segment) || isDiff;
|
|
29
28
|
});
|
|
30
29
|
removed.forEach(function (segment) {
|
|
31
|
-
|
|
30
|
+
isDiff = _this.removeSegment(segment) || isDiff;
|
|
32
31
|
});
|
|
33
|
-
return isDiff_1;
|
|
34
|
-
}
|
|
35
|
-
var names = (segmentsData.k || []).map(function (s) { return s.n; }).sort();
|
|
36
|
-
var storedSegmentKeys = this.getRegisteredSegments().sort();
|
|
37
|
-
// Extreme fast => everything is empty
|
|
38
|
-
if (!names.length && !storedSegmentKeys.length)
|
|
39
|
-
return false;
|
|
40
|
-
var index = 0;
|
|
41
|
-
while (index < names.length && index < storedSegmentKeys.length && names[index] === storedSegmentKeys[index])
|
|
42
|
-
index++;
|
|
43
|
-
// Quick path => no changes
|
|
44
|
-
if (index === names.length && index === storedSegmentKeys.length)
|
|
45
|
-
return false;
|
|
46
|
-
// Slowest path => add and/or remove segments
|
|
47
|
-
for (var removeIndex = index; removeIndex < storedSegmentKeys.length; removeIndex++) {
|
|
48
|
-
this.removeSegment(storedSegmentKeys[removeIndex]);
|
|
49
32
|
}
|
|
50
|
-
|
|
51
|
-
|
|
33
|
+
else {
|
|
34
|
+
var names = (segmentsData.k || []).map(function (s) { return s.n; }).sort();
|
|
35
|
+
var storedSegmentKeys = this.getRegisteredSegments().sort();
|
|
36
|
+
// Extreme fast => everything is empty
|
|
37
|
+
if (!names.length && !storedSegmentKeys.length) {
|
|
38
|
+
isDiff = false;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
var index = 0;
|
|
42
|
+
while (index < names.length && index < storedSegmentKeys.length && names[index] === storedSegmentKeys[index])
|
|
43
|
+
index++;
|
|
44
|
+
// Quick path => no changes
|
|
45
|
+
if (index === names.length && index === storedSegmentKeys.length) {
|
|
46
|
+
isDiff = false;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Slowest path => add and/or remove segments
|
|
50
|
+
for (var removeIndex = index; removeIndex < storedSegmentKeys.length; removeIndex++) {
|
|
51
|
+
this.removeSegment(storedSegmentKeys[removeIndex]);
|
|
52
|
+
}
|
|
53
|
+
for (var addIndex = index; addIndex < names.length; addIndex++) {
|
|
54
|
+
this.addSegment(names[addIndex]);
|
|
55
|
+
}
|
|
56
|
+
isDiff = true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
52
59
|
}
|
|
53
|
-
|
|
60
|
+
this.setChangeNumber(segmentsData.cn);
|
|
61
|
+
return isDiff;
|
|
54
62
|
};
|
|
55
63
|
return AbstractMySegmentsCacheSync;
|
|
56
64
|
}());
|
|
@@ -9,9 +9,10 @@ var AbstractSplitsCacheSync = /** @class */ (function () {
|
|
|
9
9
|
}
|
|
10
10
|
AbstractSplitsCacheSync.prototype.update = function (toAdd, toRemove, changeNumber) {
|
|
11
11
|
var _this = this;
|
|
12
|
-
this.setChangeNumber(changeNumber);
|
|
13
12
|
var updated = toAdd.map(function (addedFF) { return _this.addSplit(addedFF); }).some(function (result) { return result; });
|
|
14
|
-
|
|
13
|
+
updated = toRemove.map(function (removedFF) { return _this.removeSplit(removedFF.name); }).some(function (result) { return result; }) || updated;
|
|
14
|
+
this.setChangeNumber(changeNumber);
|
|
15
|
+
return updated;
|
|
15
16
|
};
|
|
16
17
|
AbstractSplitsCacheSync.prototype.getSplits = function (names) {
|
|
17
18
|
var _this = this;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __extends } from "tslib";
|
|
2
2
|
import { isNaNNumber } from '../../utils/lang';
|
|
3
3
|
import { AbstractMySegmentsCacheSync } from '../AbstractMySegmentsCacheSync';
|
|
4
|
-
import {
|
|
4
|
+
import { DEFINED } from './constants';
|
|
5
5
|
var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
6
6
|
__extends(MySegmentsCacheInLocal, _super);
|
|
7
7
|
function MySegmentsCacheInLocal(log, keys, storage) {
|
|
@@ -10,33 +10,20 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
10
10
|
_this.keys = keys;
|
|
11
11
|
_this.storage = storage;
|
|
12
12
|
return _this;
|
|
13
|
-
// There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
|
|
14
13
|
}
|
|
15
14
|
MySegmentsCacheInLocal.prototype.addSegment = function (name) {
|
|
16
15
|
var segmentKey = this.keys.buildSegmentNameKey(name);
|
|
17
|
-
|
|
18
|
-
if (this.storage.getItem(segmentKey) === DEFINED)
|
|
19
|
-
return false;
|
|
20
|
-
this.storage.setItem(segmentKey, DEFINED);
|
|
21
|
-
return true;
|
|
22
|
-
}
|
|
23
|
-
catch (e) {
|
|
24
|
-
this.log.error(LOG_PREFIX + e);
|
|
16
|
+
if (this.storage.getItem(segmentKey) === DEFINED)
|
|
25
17
|
return false;
|
|
26
|
-
|
|
18
|
+
this.storage.setItem(segmentKey, DEFINED);
|
|
19
|
+
return true;
|
|
27
20
|
};
|
|
28
21
|
MySegmentsCacheInLocal.prototype.removeSegment = function (name) {
|
|
29
22
|
var segmentKey = this.keys.buildSegmentNameKey(name);
|
|
30
|
-
|
|
31
|
-
if (this.storage.getItem(segmentKey) !== DEFINED)
|
|
32
|
-
return false;
|
|
33
|
-
this.storage.removeItem(segmentKey);
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
catch (e) {
|
|
37
|
-
this.log.error(LOG_PREFIX + e);
|
|
23
|
+
if (this.storage.getItem(segmentKey) !== DEFINED)
|
|
38
24
|
return false;
|
|
39
|
-
|
|
25
|
+
this.storage.removeItem(segmentKey);
|
|
26
|
+
return true;
|
|
40
27
|
};
|
|
41
28
|
MySegmentsCacheInLocal.prototype.isInSegment = function (name) {
|
|
42
29
|
return this.storage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
|
|
@@ -54,15 +41,10 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
|
|
|
54
41
|
return 1;
|
|
55
42
|
};
|
|
56
43
|
MySegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
this.storage.removeItem(this.keys.buildTillKey());
|
|
62
|
-
}
|
|
63
|
-
catch (e) {
|
|
64
|
-
this.log.error(e);
|
|
65
|
-
}
|
|
44
|
+
if (changeNumber)
|
|
45
|
+
this.storage.setItem(this.keys.buildTillKey(), changeNumber + '');
|
|
46
|
+
else
|
|
47
|
+
this.storage.removeItem(this.keys.buildTillKey());
|
|
66
48
|
};
|
|
67
49
|
MySegmentsCacheInLocal.prototype.getChangeNumber = function () {
|
|
68
50
|
var n = -1;
|