@splitsoftware/splitio-commons 1.5.0 → 1.5.1-rc.2
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 +5 -0
- package/cjs/listeners/browser.js +35 -15
- package/cjs/services/splitApi.js +4 -4
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +5 -5
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +2 -2
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +34 -34
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +4 -3
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +46 -46
- package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +82 -64
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +74 -58
- package/cjs/sync/streaming/UpdateWorkers/constants.js +6 -0
- package/cjs/sync/streaming/pushManager.js +6 -7
- package/cjs/sync/syncTask.js +13 -16
- package/cjs/utils/Backoff.js +3 -2
- package/esm/listeners/browser.js +35 -15
- package/esm/services/splitApi.js +4 -4
- package/esm/sync/polling/fetchers/segmentChangesFetcher.js +5 -5
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +2 -2
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +34 -34
- package/esm/sync/polling/updaters/splitChangesUpdater.js +4 -3
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +46 -47
- package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +82 -65
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +74 -59
- package/esm/sync/streaming/UpdateWorkers/constants.js +3 -0
- package/esm/sync/streaming/pushManager.js +6 -7
- package/esm/sync/syncTask.js +13 -16
- package/esm/utils/Backoff.js +3 -2
- package/package.json +1 -5
- package/src/listeners/browser.ts +34 -14
- package/src/logger/.DS_Store +0 -0
- package/src/services/splitApi.ts +4 -4
- package/src/services/types.ts +2 -2
- package/src/sync/polling/fetchers/segmentChangesFetcher.ts +5 -4
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +2 -1
- package/src/sync/polling/fetchers/types.ts +2 -0
- package/src/sync/polling/pollingManagerCS.ts +5 -5
- package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +2 -2
- package/src/sync/polling/types.ts +14 -6
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +4 -4
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +34 -32
- package/src/sync/polling/updaters/splitChangesUpdater.ts +5 -4
- package/src/sync/streaming/SSEHandler/types.ts +0 -7
- package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +45 -54
- package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +78 -63
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +73 -61
- package/src/sync/streaming/UpdateWorkers/constants.ts +3 -0
- package/src/sync/streaming/UpdateWorkers/types.ts +2 -4
- package/src/sync/streaming/pushManager.ts +12 -12
- package/src/sync/streaming/types.ts +2 -2
- package/src/sync/syncTask.ts +16 -18
- package/src/utils/Backoff.ts +7 -2
- package/types/integrations/ga/GaToSplitPlugin.d.ts +3 -0
- package/types/integrations/ga/SplitToGaPlugin.d.ts +4 -0
- package/types/integrations/ga/autoRequire.d.ts +4 -0
- package/types/listeners/browser.d.ts +6 -6
- package/types/logger/browser/{DebugLogger.d.ts → debugLogger.d.ts} +0 -0
- package/types/logger/browser/{ErrorLogger.d.ts → errorLogger.d.ts} +0 -0
- package/types/logger/browser/{InfoLogger.d.ts → infoLogger.d.ts} +0 -0
- package/types/logger/browser/{WarnLogger.d.ts → warnLogger.d.ts} +0 -0
- package/types/logger/codes.d.ts +2 -0
- package/types/logger/codesConstants.d.ts +117 -0
- package/types/logger/codesConstantsBrowser.d.ts +2 -0
- package/types/logger/codesConstantsNode.d.ts +14 -0
- package/types/logger/codesDebug.d.ts +1 -0
- package/types/logger/codesDebugBrowser.d.ts +1 -0
- package/types/logger/codesDebugNode.d.ts +1 -0
- package/types/logger/codesError.d.ts +1 -0
- package/types/logger/codesErrorNode.d.ts +1 -0
- package/types/logger/codesInfo.d.ts +1 -0
- package/types/logger/codesWarn.d.ts +1 -0
- package/types/logger/codesWarnNode.d.ts +1 -0
- package/types/logger/debugLogger.d.ts +2 -0
- package/types/logger/errorLogger.d.ts +2 -0
- package/types/logger/infoLogger.d.ts +2 -0
- package/types/logger/messages/debugBrowser.d.ts +1 -0
- package/types/logger/messages/debugNode.d.ts +1 -0
- package/types/logger/messages/errorNode.d.ts +1 -0
- package/types/logger/messages/warnNode.d.ts +1 -0
- package/types/logger/noopLogger.d.ts +2 -0
- package/types/logger/warnLogger.d.ts +2 -0
- package/types/sdkFactory/userConsentProps.d.ts +6 -0
- package/types/sdkManager/sdkManagerMethod.d.ts +6 -0
- package/types/services/types.d.ts +2 -2
- package/types/storages/getRegisteredSegments.d.ts +10 -0
- package/types/storages/inMemory/index.d.ts +10 -0
- package/types/storages/parseSegments.d.ts +6 -0
- package/types/sync/polling/fetchers/types.d.ts +2 -2
- package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +2 -2
- package/types/sync/polling/syncTasks/splitsSyncTask.copy.d.ts +35 -0
- package/types/sync/polling/syncTasks/splitsSyncTask.morelikeoriginal.d.ts +35 -0
- package/types/sync/polling/types.d.ts +11 -6
- package/types/sync/polling/updaters/segmentChangesUpdater.d.ts +1 -1
- package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -1
- package/types/sync/streaming/AuthClient/indexV1.d.ts +12 -0
- package/types/sync/streaming/AuthClient/indexV2.d.ts +8 -0
- package/types/sync/streaming/SSEHandler/types.d.ts +0 -4
- package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +3 -24
- package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +3 -23
- package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +6 -33
- package/types/sync/streaming/UpdateWorkers/constants.d.ts +3 -0
- package/types/sync/streaming/UpdateWorkers/types.d.ts +1 -2
- package/types/sync/streaming/pushManagerCS.d.ts +1 -0
- package/types/sync/streaming/pushManagerNoUsers.d.ts +13 -0
- package/types/sync/streaming/pushManagerSS.d.ts +1 -0
- package/types/sync/streaming/types.d.ts +2 -2
- package/types/sync/submitters/telemetrySyncTask.d.ts +0 -0
- package/types/sync/syncManagerFromFile.d.ts +2 -0
- package/types/sync/syncManagerFromObject.d.ts +2 -0
- package/types/sync/syncManagerOffline.d.ts +9 -0
- package/types/sync/syncTask.d.ts +2 -3
- package/types/trackers/telemetryRecorder.d.ts +0 -0
- package/types/utils/Backoff.d.ts +2 -0
- package/types/utils/EventEmitter.d.ts +4 -0
- package/types/utils/consent.d.ts +2 -0
- package/types/utils/lang/errors.d.ts +10 -0
- package/types/utils/murmur3/commons.d.ts +12 -0
- package/types/utils/settingsValidation/buildMetadata.d.ts +3 -0
- package/types/utils/settingsValidation/localhost/index.d.ts +9 -0
- package/types/utils/settingsValidation/logger.d.ts +11 -0
- package/types/utils/settingsValidation/runtime/browser.d.ts +2 -0
- package/types/utils/settingsValidation/runtime/node.d.ts +2 -0
- package/types/utils/settingsValidation/userConsent.d.ts +5 -0
- package/types/utils/timeTracker/index.d.ts +1 -70
- package/cjs/sync/offline/LocalhostFromFile.js +0 -13
- package/cjs/sync/offline/splitsParser/splitsParserFromFile.js +0 -151
- package/esm/sync/offline/LocalhostFromFile.js +0 -9
- package/esm/sync/offline/splitsParser/splitsParserFromFile.js +0 -146
- package/src/sync/offline/LocalhostFromFile.ts +0 -12
- package/src/sync/offline/splitsParser/splitsParserFromFile.ts +0 -182
|
@@ -1,58 +1,57 @@
|
|
|
1
1
|
import { Backoff } from '../../../utils/Backoff';
|
|
2
2
|
/**
|
|
3
|
-
* MySegmentsUpdateWorker
|
|
3
|
+
* MySegmentsUpdateWorker factory
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
this.backoff = new Backoff(this.__handleMySegmentsUpdateCall);
|
|
18
|
-
}
|
|
19
|
-
// Private method
|
|
20
|
-
// Precondition: this.mySegmentsSyncTask.isSynchronizingMySegments === false
|
|
21
|
-
MySegmentsUpdateWorker.prototype.__handleMySegmentsUpdateCall = function () {
|
|
22
|
-
var _this = this;
|
|
23
|
-
if (this.maxChangeNumber > this.currentChangeNumber) {
|
|
24
|
-
this.handleNewEvent = false;
|
|
25
|
-
var currentMaxChangeNumber_1 = this.maxChangeNumber;
|
|
5
|
+
export function MySegmentsUpdateWorker(mySegmentsSyncTask) {
|
|
6
|
+
var maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
|
|
7
|
+
var currentChangeNumber = -1;
|
|
8
|
+
var handleNewEvent = false;
|
|
9
|
+
var isHandlingEvent;
|
|
10
|
+
var _segmentsData; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber
|
|
11
|
+
var backoff = new Backoff(__handleMySegmentsUpdateCall);
|
|
12
|
+
function __handleMySegmentsUpdateCall() {
|
|
13
|
+
isHandlingEvent = true;
|
|
14
|
+
if (maxChangeNumber > currentChangeNumber) {
|
|
15
|
+
handleNewEvent = false;
|
|
16
|
+
var currentMaxChangeNumber_1 = maxChangeNumber;
|
|
26
17
|
// fetch mySegments revalidating data if cached
|
|
27
|
-
|
|
18
|
+
mySegmentsSyncTask.execute(_segmentsData, true).then(function (result) {
|
|
19
|
+
if (!isHandlingEvent)
|
|
20
|
+
return; // halt if `stop` has been called
|
|
28
21
|
if (result !== false) // Unlike `Splits|SegmentsUpdateWorker`, we cannot use `mySegmentsCache.getChangeNumber` since `/mySegments` endpoint doesn't provide this value.
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
|
|
22
|
+
currentChangeNumber = Math.max(currentChangeNumber, currentMaxChangeNumber_1); // use `currentMaxChangeNumber`, in case that `maxChangeNumber` was updated during fetch.
|
|
23
|
+
if (handleNewEvent) {
|
|
24
|
+
__handleMySegmentsUpdateCall();
|
|
32
25
|
}
|
|
33
26
|
else {
|
|
34
|
-
|
|
27
|
+
backoff.scheduleCall();
|
|
35
28
|
}
|
|
36
29
|
});
|
|
37
30
|
}
|
|
31
|
+
else {
|
|
32
|
+
isHandlingEvent = false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
/**
|
|
37
|
+
* Invoked by NotificationProcessor on MY_SEGMENTS_UPDATE event
|
|
38
|
+
*
|
|
39
|
+
* @param {number} changeNumber change number of the MY_SEGMENTS_UPDATE notification
|
|
40
|
+
* @param {SegmentsData | undefined} segmentsData might be undefined
|
|
41
|
+
*/
|
|
42
|
+
put: function (changeNumber, segmentsData) {
|
|
43
|
+
if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber)
|
|
44
|
+
return;
|
|
45
|
+
maxChangeNumber = changeNumber;
|
|
46
|
+
handleNewEvent = true;
|
|
47
|
+
_segmentsData = segmentsData;
|
|
48
|
+
if (backoff.timeoutID || !isHandlingEvent)
|
|
49
|
+
__handleMySegmentsUpdateCall();
|
|
50
|
+
backoff.reset();
|
|
51
|
+
},
|
|
52
|
+
stop: function () {
|
|
53
|
+
isHandlingEvent = false;
|
|
54
|
+
backoff.reset();
|
|
55
|
+
}
|
|
38
56
|
};
|
|
39
|
-
|
|
40
|
-
* Invoked by NotificationProcessor on MY_SEGMENTS_UPDATE event
|
|
41
|
-
*
|
|
42
|
-
* @param {number} changeNumber change number of the MY_SEGMENTS_UPDATE notification
|
|
43
|
-
* @param {SegmentsData | undefined} segmentsData might be undefined
|
|
44
|
-
*/
|
|
45
|
-
MySegmentsUpdateWorker.prototype.put = function (changeNumber, segmentsData) {
|
|
46
|
-
if (changeNumber <= this.currentChangeNumber || changeNumber <= this.maxChangeNumber)
|
|
47
|
-
return;
|
|
48
|
-
this.maxChangeNumber = changeNumber;
|
|
49
|
-
this.handleNewEvent = true;
|
|
50
|
-
this.backoff.reset();
|
|
51
|
-
this.segmentsData = segmentsData;
|
|
52
|
-
if (this.mySegmentsSyncTask.isExecuting())
|
|
53
|
-
return;
|
|
54
|
-
this.__handleMySegmentsUpdateCall();
|
|
55
|
-
};
|
|
56
|
-
return MySegmentsUpdateWorker;
|
|
57
|
-
}());
|
|
58
|
-
export { MySegmentsUpdateWorker };
|
|
57
|
+
}
|
|
@@ -1,71 +1,88 @@
|
|
|
1
1
|
import { Backoff } from '../../../utils/Backoff';
|
|
2
|
+
import { FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_RETRIES, FETCH_BACKOFF_MAX_WAIT } from './constants';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
+
* SegmentsUpdateWorker factory
|
|
4
5
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
export function SegmentsUpdateWorker(log, segmentsSyncTask, segmentsCache) {
|
|
7
|
+
// Handles retries with CDN bypass per segment name
|
|
8
|
+
function SegmentUpdateWorker(segment) {
|
|
9
|
+
var maxChangeNumber = 0;
|
|
10
|
+
var handleNewEvent = false;
|
|
11
|
+
var isHandlingEvent;
|
|
12
|
+
var cdnBypass;
|
|
13
|
+
var backoff = new Backoff(__handleSegmentUpdateCall, FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT);
|
|
14
|
+
function __handleSegmentUpdateCall() {
|
|
15
|
+
isHandlingEvent = true;
|
|
16
|
+
if (maxChangeNumber > segmentsCache.getChangeNumber(segment)) {
|
|
17
|
+
handleNewEvent = false;
|
|
18
|
+
// fetch segments revalidating data if cached
|
|
19
|
+
segmentsSyncTask.execute(false, segment, true, cdnBypass ? maxChangeNumber : undefined).then(function () {
|
|
20
|
+
if (!isHandlingEvent)
|
|
21
|
+
return; // halt if `stop` has been called
|
|
22
|
+
if (handleNewEvent) {
|
|
23
|
+
__handleSegmentUpdateCall();
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
var attempts = backoff.attempts + 1;
|
|
27
|
+
if (maxChangeNumber <= segmentsCache.getChangeNumber(segment)) {
|
|
28
|
+
log.debug("Refresh completed" + (cdnBypass ? ' bypassing the CDN' : '') + " in " + attempts + " attempts.");
|
|
29
|
+
isHandlingEvent = false;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (attempts < FETCH_BACKOFF_MAX_RETRIES) {
|
|
33
|
+
backoff.scheduleCall();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (cdnBypass) {
|
|
37
|
+
log.debug("No changes fetched after " + attempts + " attempts with CDN bypassed.");
|
|
38
|
+
isHandlingEvent = false;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
backoff.reset();
|
|
42
|
+
cdnBypass = true;
|
|
43
|
+
__handleSegmentUpdateCall();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
isHandlingEvent = false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
put: function (changeNumber) {
|
|
54
|
+
var currentChangeNumber = segmentsCache.getChangeNumber(segment);
|
|
55
|
+
if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber)
|
|
56
|
+
return;
|
|
57
|
+
maxChangeNumber = changeNumber;
|
|
58
|
+
handleNewEvent = true;
|
|
59
|
+
cdnBypass = false;
|
|
60
|
+
if (backoff.timeoutID || !isHandlingEvent)
|
|
61
|
+
__handleSegmentUpdateCall();
|
|
62
|
+
backoff.reset();
|
|
63
|
+
},
|
|
64
|
+
stop: function () {
|
|
65
|
+
isHandlingEvent = false;
|
|
66
|
+
backoff.reset();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
18
69
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
segmentsToFetch.forEach(function (fetchedSegment, index) {
|
|
36
|
-
if (_this.maxChangeNumbers[fetchedSegment] === currentMaxChangeNumbers_1[index])
|
|
37
|
-
_this.maxChangeNumbers[fetchedSegment] = -1;
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
// recursive invocation with backoff if there was some error
|
|
42
|
-
_this.backoff.scheduleCall();
|
|
43
|
-
}
|
|
44
|
-
// immediate recursive invocation if a new notification was queued during fetch
|
|
45
|
-
if (_this.handleNewEvent) {
|
|
46
|
-
_this.__handleSegmentUpdateCall();
|
|
47
|
-
}
|
|
48
|
-
});
|
|
70
|
+
var segments = {};
|
|
71
|
+
return {
|
|
72
|
+
/**
|
|
73
|
+
* Invoked by NotificationProcessor on SEGMENT_UPDATE event
|
|
74
|
+
*
|
|
75
|
+
* @param {number} changeNumber change number of the SEGMENT_UPDATE notification
|
|
76
|
+
* @param {string} segmentName segment name of the SEGMENT_UPDATE notification
|
|
77
|
+
*/
|
|
78
|
+
put: function (_a) {
|
|
79
|
+
var changeNumber = _a.changeNumber, segmentName = _a.segmentName;
|
|
80
|
+
if (!segments[segmentName])
|
|
81
|
+
segments[segmentName] = SegmentUpdateWorker(segmentName);
|
|
82
|
+
segments[segmentName].put(changeNumber);
|
|
83
|
+
},
|
|
84
|
+
stop: function () {
|
|
85
|
+
Object.keys(segments).forEach(function (segmentName) { return segments[segmentName].stop(); });
|
|
49
86
|
}
|
|
50
87
|
};
|
|
51
|
-
|
|
52
|
-
* Invoked by NotificationProcessor on SEGMENT_UPDATE event
|
|
53
|
-
*
|
|
54
|
-
* @param {number} changeNumber change number of the SEGMENT_UPDATE notification
|
|
55
|
-
* @param {string} segmentName segment name of the SEGMENT_UPDATE notification
|
|
56
|
-
*/
|
|
57
|
-
SegmentsUpdateWorker.prototype.put = function (_a) {
|
|
58
|
-
var changeNumber = _a.changeNumber, segmentName = _a.segmentName;
|
|
59
|
-
var currentChangeNumber = this.segmentsCache.getChangeNumber(segmentName);
|
|
60
|
-
if (changeNumber <= currentChangeNumber || changeNumber <= this.maxChangeNumbers[segmentName])
|
|
61
|
-
return;
|
|
62
|
-
this.maxChangeNumbers[segmentName] = changeNumber;
|
|
63
|
-
this.handleNewEvent = true;
|
|
64
|
-
this.backoff.reset();
|
|
65
|
-
if (this.segmentsSyncTask.isExecuting())
|
|
66
|
-
return;
|
|
67
|
-
this.__handleSegmentUpdateCall();
|
|
68
|
-
};
|
|
69
|
-
return SegmentsUpdateWorker;
|
|
70
|
-
}());
|
|
71
|
-
export { SegmentsUpdateWorker };
|
|
88
|
+
}
|
|
@@ -1,79 +1,94 @@
|
|
|
1
1
|
import { SDK_SPLITS_ARRIVED } from '../../../readiness/constants';
|
|
2
2
|
import { Backoff } from '../../../utils/Backoff';
|
|
3
|
+
import { FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT, FETCH_BACKOFF_MAX_RETRIES } from './constants';
|
|
3
4
|
/**
|
|
4
|
-
* SplitsUpdateWorker
|
|
5
|
+
* SplitsUpdateWorker factory
|
|
5
6
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
this.segmentsSyncTask = segmentsSyncTask;
|
|
17
|
-
this.maxChangeNumber = 0;
|
|
18
|
-
this.handleNewEvent = false;
|
|
19
|
-
this.put = this.put.bind(this);
|
|
20
|
-
this.killSplit = this.killSplit.bind(this);
|
|
21
|
-
this.__handleSplitUpdateCall = this.__handleSplitUpdateCall.bind(this);
|
|
22
|
-
this.backoff = new Backoff(this.__handleSplitUpdateCall);
|
|
23
|
-
}
|
|
24
|
-
// Private method
|
|
25
|
-
// Preconditions: this.splitsSyncTask.isSynchronizingSplits === false
|
|
26
|
-
SplitsUpdateWorker.prototype.__handleSplitUpdateCall = function () {
|
|
27
|
-
var _this = this;
|
|
28
|
-
if (this.maxChangeNumber > this.splitsCache.getChangeNumber()) {
|
|
29
|
-
this.handleNewEvent = false;
|
|
7
|
+
export function SplitsUpdateWorker(log, splitsCache, splitsSyncTask, splitsEventEmitter, segmentsSyncTask) {
|
|
8
|
+
var maxChangeNumber = 0;
|
|
9
|
+
var handleNewEvent = false;
|
|
10
|
+
var isHandlingEvent;
|
|
11
|
+
var cdnBypass;
|
|
12
|
+
var backoff = new Backoff(__handleSplitUpdateCall, FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT);
|
|
13
|
+
function __handleSplitUpdateCall() {
|
|
14
|
+
isHandlingEvent = true;
|
|
15
|
+
if (maxChangeNumber > splitsCache.getChangeNumber()) {
|
|
16
|
+
handleNewEvent = false;
|
|
30
17
|
// fetch splits revalidating data if cached
|
|
31
|
-
|
|
32
|
-
if (
|
|
33
|
-
|
|
18
|
+
splitsSyncTask.execute(true, cdnBypass ? maxChangeNumber : undefined).then(function () {
|
|
19
|
+
if (!isHandlingEvent)
|
|
20
|
+
return; // halt if `stop` has been called
|
|
21
|
+
if (handleNewEvent) {
|
|
22
|
+
__handleSplitUpdateCall();
|
|
34
23
|
}
|
|
35
24
|
else {
|
|
36
25
|
// fetch new registered segments for server-side API. Not retrying on error
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
26
|
+
if (segmentsSyncTask)
|
|
27
|
+
segmentsSyncTask.execute(true);
|
|
28
|
+
var attempts = backoff.attempts + 1;
|
|
29
|
+
if (maxChangeNumber <= splitsCache.getChangeNumber()) {
|
|
30
|
+
log.debug("Refresh completed" + (cdnBypass ? ' bypassing the CDN' : '') + " in " + attempts + " attempts.");
|
|
31
|
+
isHandlingEvent = false;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (attempts < FETCH_BACKOFF_MAX_RETRIES) {
|
|
35
|
+
backoff.scheduleCall();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (cdnBypass) {
|
|
39
|
+
log.debug("No changes fetched after " + attempts + " attempts with CDN bypassed.");
|
|
40
|
+
isHandlingEvent = false;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
backoff.reset();
|
|
44
|
+
cdnBypass = true;
|
|
45
|
+
__handleSplitUpdateCall();
|
|
46
|
+
}
|
|
40
47
|
}
|
|
41
48
|
});
|
|
42
49
|
}
|
|
43
|
-
|
|
50
|
+
else {
|
|
51
|
+
isHandlingEvent = false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
44
54
|
/**
|
|
45
55
|
* Invoked by NotificationProcessor on SPLIT_UPDATE event
|
|
46
56
|
*
|
|
47
57
|
* @param {number} changeNumber change number of the SPLIT_UPDATE notification
|
|
48
58
|
*/
|
|
49
|
-
|
|
59
|
+
function put(_a) {
|
|
50
60
|
var changeNumber = _a.changeNumber;
|
|
51
|
-
var currentChangeNumber =
|
|
52
|
-
if (changeNumber <= currentChangeNumber || changeNumber <=
|
|
53
|
-
return;
|
|
54
|
-
this.maxChangeNumber = changeNumber;
|
|
55
|
-
this.handleNewEvent = true;
|
|
56
|
-
this.backoff.reset();
|
|
57
|
-
if (this.splitsSyncTask.isExecuting())
|
|
61
|
+
var currentChangeNumber = splitsCache.getChangeNumber();
|
|
62
|
+
if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber)
|
|
58
63
|
return;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
maxChangeNumber = changeNumber;
|
|
65
|
+
handleNewEvent = true;
|
|
66
|
+
cdnBypass = false;
|
|
67
|
+
if (backoff.timeoutID || !isHandlingEvent)
|
|
68
|
+
__handleSplitUpdateCall();
|
|
69
|
+
backoff.reset();
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
put: put,
|
|
73
|
+
/**
|
|
74
|
+
* Invoked by NotificationProcessor on SPLIT_KILL event
|
|
75
|
+
*
|
|
76
|
+
* @param {number} changeNumber change number of the SPLIT_UPDATE notification
|
|
77
|
+
* @param {string} splitName name of split to kill
|
|
78
|
+
* @param {string} defaultTreatment default treatment value
|
|
79
|
+
*/
|
|
80
|
+
killSplit: function (_a) {
|
|
81
|
+
var changeNumber = _a.changeNumber, splitName = _a.splitName, defaultTreatment = _a.defaultTreatment;
|
|
82
|
+
if (splitsCache.killLocally(splitName, defaultTreatment, changeNumber)) {
|
|
83
|
+
// trigger an SDK_UPDATE if Split was killed locally
|
|
84
|
+
splitsEventEmitter.emit(SDK_SPLITS_ARRIVED, true);
|
|
85
|
+
}
|
|
86
|
+
// queues the SplitChanges fetch (only if changeNumber is newer)
|
|
87
|
+
put({ changeNumber: changeNumber });
|
|
88
|
+
},
|
|
89
|
+
stop: function () {
|
|
90
|
+
isHandlingEvent = false;
|
|
91
|
+
backoff.reset();
|
|
73
92
|
}
|
|
74
|
-
// queues the SplitChanges fetch (only if changeNumber is newer)
|
|
75
|
-
this.put({ changeNumber: changeNumber });
|
|
76
93
|
};
|
|
77
|
-
|
|
78
|
-
}());
|
|
79
|
-
export { SplitsUpdateWorker };
|
|
94
|
+
}
|
|
@@ -42,9 +42,9 @@ export function pushManagerFactory(params, pollingManager) {
|
|
|
42
42
|
sseClient.setEventHandler(sseHandler);
|
|
43
43
|
// init workers
|
|
44
44
|
// MySegmentsUpdateWorker (client-side) are initiated in `add` method
|
|
45
|
-
var segmentsUpdateWorker = userKey ? undefined :
|
|
45
|
+
var segmentsUpdateWorker = userKey ? undefined : SegmentsUpdateWorker(log, pollingManager.segmentsSyncTask, storage.segments);
|
|
46
46
|
// For server-side we pass the segmentsSyncTask, used by SplitsUpdateWorker to fetch new segments
|
|
47
|
-
var splitsUpdateWorker =
|
|
47
|
+
var splitsUpdateWorker = SplitsUpdateWorker(log, storage.splits, pollingManager.splitsSyncTask, readiness.splits, userKey ? undefined : pollingManager.segmentsSyncTask);
|
|
48
48
|
// [Only for client-side] map of hashes to user keys, to dispatch MY_SEGMENTS_UPDATE events to the corresponding MySegmentsUpdateWorker
|
|
49
49
|
var userKeyHashes = {};
|
|
50
50
|
// [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
|
|
@@ -137,21 +137,20 @@ export function pushManagerFactory(params, pollingManager) {
|
|
|
137
137
|
}
|
|
138
138
|
// cancel scheduled fetch retries of Splits, Segments, and MySegments Update Workers
|
|
139
139
|
function stopWorkers() {
|
|
140
|
-
splitsUpdateWorker.
|
|
140
|
+
splitsUpdateWorker.stop();
|
|
141
141
|
if (userKey)
|
|
142
142
|
forOwn(clients, function (_a) {
|
|
143
143
|
var worker = _a.worker;
|
|
144
|
-
return worker.
|
|
144
|
+
return worker.stop();
|
|
145
145
|
});
|
|
146
146
|
else
|
|
147
|
-
segmentsUpdateWorker.
|
|
147
|
+
segmentsUpdateWorker.stop();
|
|
148
148
|
}
|
|
149
149
|
pushEmitter.on(PUSH_SUBSYSTEM_DOWN, stopWorkers);
|
|
150
150
|
// Only required when streaming connects after a PUSH_RETRYABLE_ERROR.
|
|
151
151
|
// Otherwise it is unnecessary (e.g, STREAMING_RESUMED).
|
|
152
152
|
pushEmitter.on(PUSH_SUBSYSTEM_UP, function () {
|
|
153
153
|
connectPushRetryBackoff.reset();
|
|
154
|
-
stopWorkers();
|
|
155
154
|
});
|
|
156
155
|
/** Fallback to polling without retry due to: STREAMING_DISABLED control event, or 'pushEnabled: false', or non-recoverable SSE and Authentication errors */
|
|
157
156
|
pushEmitter.on(PUSH_NONRETRYABLE_ERROR, function handleNonRetryableError() {
|
|
@@ -287,7 +286,7 @@ export function pushManagerFactory(params, pollingManager) {
|
|
|
287
286
|
var hash = hashUserKey(userKey);
|
|
288
287
|
if (!userKeyHashes[hash]) {
|
|
289
288
|
userKeyHashes[hash] = userKey;
|
|
290
|
-
clients[userKey] = { hash64: hash64(userKey), worker:
|
|
289
|
+
clients[userKey] = { hash64: hash64(userKey), worker: MySegmentsUpdateWorker(mySegmentsSyncTask) };
|
|
291
290
|
connectForNewClient = true; // we must reconnect on start, to listen the channel for the new user key
|
|
292
291
|
// Reconnects in case of a new client.
|
|
293
292
|
// Run in next event-loop cycle to save authentication calls
|
package/esm/sync/syncTask.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { SYNC_TASK_EXECUTE, SYNC_TASK_START, SYNC_TASK_STOP } from '../logger/constants';
|
|
2
2
|
/**
|
|
3
|
-
* Creates
|
|
4
|
-
* The task can be also executed by calling the "execute" method. Multiple
|
|
5
|
-
* For example, submitters executed on SDK destroy or full queue, while periodic execution is pending.
|
|
3
|
+
* Creates an object that handles the periodic execution of a given task via "start" and "stop" methods.
|
|
4
|
+
* The task can be also executed by calling the "execute" method. Multiple calls run sequentially to avoid race conditions (e.g., submitters executed on SDK destroy or full queue, while periodic execution is pending).
|
|
6
5
|
*
|
|
7
6
|
* @param log Logger instance.
|
|
8
7
|
* @param task Task to execute that returns a promise that NEVER REJECTS. Otherwise, periodic execution can result in Unhandled Promise Rejections.
|
|
@@ -12,8 +11,10 @@ import { SYNC_TASK_EXECUTE, SYNC_TASK_START, SYNC_TASK_STOP } from '../logger/co
|
|
|
12
11
|
*/
|
|
13
12
|
export function syncTaskFactory(log, task, period, taskName) {
|
|
14
13
|
if (taskName === void 0) { taskName = 'task'; }
|
|
15
|
-
//
|
|
16
|
-
var
|
|
14
|
+
// Flag that indicates if the task is executing
|
|
15
|
+
var executing = 0;
|
|
16
|
+
// Promise chain to resolve tasks sequentially
|
|
17
|
+
var promiseChain;
|
|
17
18
|
// flag that indicates if the task periodic execution has been started/stopped.
|
|
18
19
|
var running = false;
|
|
19
20
|
// Auxiliar counter used to avoid race condition when calling `start` & `stop` intermittently
|
|
@@ -27,19 +28,15 @@ export function syncTaskFactory(log, task, period, taskName) {
|
|
|
27
28
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
28
29
|
args[_i] = arguments[_i];
|
|
29
30
|
}
|
|
30
|
-
|
|
31
|
-
if (pendingTask) {
|
|
32
|
-
return pendingTask.then(function () {
|
|
33
|
-
return execute.apply(void 0, args);
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
// Execute task
|
|
31
|
+
executing++;
|
|
37
32
|
log.debug(SYNC_TASK_EXECUTE, [taskName]);
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
// Update `promiseChain` with last promise, to run tasks serially
|
|
34
|
+
promiseChain = (promiseChain ? promiseChain.then(function () { return task.apply(void 0, args); }) : task.apply(void 0, args))
|
|
35
|
+
.then(function (result) {
|
|
36
|
+
executing--;
|
|
40
37
|
return result;
|
|
41
38
|
});
|
|
42
|
-
return
|
|
39
|
+
return promiseChain;
|
|
43
40
|
}
|
|
44
41
|
function periodicExecute(currentRunningId) {
|
|
45
42
|
return execute.apply(void 0, runningArgs).then(function (result) {
|
|
@@ -53,7 +50,7 @@ export function syncTaskFactory(log, task, period, taskName) {
|
|
|
53
50
|
return {
|
|
54
51
|
execute: execute,
|
|
55
52
|
isExecuting: function () {
|
|
56
|
-
return
|
|
53
|
+
return executing > 0;
|
|
57
54
|
},
|
|
58
55
|
start: function () {
|
|
59
56
|
var args = [];
|
package/esm/utils/Backoff.js
CHANGED
|
@@ -7,8 +7,8 @@ var Backoff = /** @class */ (function () {
|
|
|
7
7
|
* @param {number} maxMillis
|
|
8
8
|
*/
|
|
9
9
|
function Backoff(cb, baseMillis, maxMillis) {
|
|
10
|
-
this.baseMillis = baseMillis || Backoff.DEFAULT_BASE_MILLIS;
|
|
11
|
-
this.maxMillis = maxMillis || Backoff.DEFAULT_MAX_MILLIS;
|
|
10
|
+
this.baseMillis = Backoff.__TEST__BASE_MILLIS || baseMillis || Backoff.DEFAULT_BASE_MILLIS;
|
|
11
|
+
this.maxMillis = Backoff.__TEST__MAX_MILLIS || maxMillis || Backoff.DEFAULT_MAX_MILLIS;
|
|
12
12
|
this.attempts = 0;
|
|
13
13
|
this.cb = cb;
|
|
14
14
|
}
|
|
@@ -22,6 +22,7 @@ var Backoff = /** @class */ (function () {
|
|
|
22
22
|
if (this.timeoutID)
|
|
23
23
|
clearTimeout(this.timeoutID);
|
|
24
24
|
this.timeoutID = setTimeout(function () {
|
|
25
|
+
_this.timeoutID = undefined;
|
|
25
26
|
_this.cb();
|
|
26
27
|
}, delayInMillis);
|
|
27
28
|
this.attempts++;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@splitsoftware/splitio-commons",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.1-rc.2",
|
|
4
4
|
"description": "Split Javascript SDK common components",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "esm/index.js",
|
|
@@ -47,13 +47,9 @@
|
|
|
47
47
|
"tslib": "^2.3.1"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"js-yaml": "^3.13.1",
|
|
51
50
|
"ioredis": "^4.28.0"
|
|
52
51
|
},
|
|
53
52
|
"peerDependenciesMeta": {
|
|
54
|
-
"js-yaml": {
|
|
55
|
-
"optional": true
|
|
56
|
-
},
|
|
57
53
|
"ioredis": {
|
|
58
54
|
"optional": true
|
|
59
55
|
}
|