@splitsoftware/splitio-commons 3.0.1-rc.2 → 3.1.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 +2 -1
- package/cjs/evaluator/condition/index.js +1 -1
- package/cjs/sync/polling/pollingManagerCS.js +1 -1
- package/cjs/sync/polling/pollingManagerSS.js +1 -1
- package/cjs/sync/polling/syncTasks/definitionsSyncTask.js +3 -2
- package/cjs/sync/polling/updaters/definitionChangesUpdater.js +4 -13
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/cjs/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.js +1 -4
- package/cjs/sync/streaming/pushManager.js +1 -1
- package/esm/evaluator/condition/index.js +1 -1
- package/esm/sync/polling/pollingManagerCS.js +1 -1
- package/esm/sync/polling/pollingManagerSS.js +1 -1
- package/esm/sync/polling/syncTasks/definitionsSyncTask.js +3 -2
- package/esm/sync/polling/updaters/definitionChangesUpdater.js +4 -13
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/esm/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.js +1 -4
- package/esm/sync/streaming/pushManager.js +1 -1
- package/package.json +1 -1
- package/src/dtos/types.ts +1 -1
- package/src/evaluator/condition/index.ts +3 -3
- package/src/sync/polling/pollingManagerCS.ts +1 -1
- package/src/sync/polling/pollingManagerSS.ts +1 -1
- package/src/sync/polling/syncTasks/definitionsSyncTask.ts +3 -3
- package/src/sync/polling/updaters/definitionChangesUpdater.ts +5 -15
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +2 -2
- package/src/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.ts +2 -4
- package/src/sync/streaming/pushManager.ts +1 -1
package/CHANGES.txt
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
3.1.0 (July
|
|
1
|
+
3.1.0 (July 23, 2026)
|
|
2
2
|
- Added support for rule-based segments in /api/v1/configs endpoint.
|
|
3
|
+
- Updated polling flow to fetch new referenced segments immediately.
|
|
3
4
|
|
|
4
5
|
3.0.0 (June 26, 2026)
|
|
5
6
|
- Extracted SDK lifecycle methods (`init`, `flush`, and `destroy`) into a reusable `sdkLifecycle` module.
|
|
@@ -10,7 +10,7 @@ function match(log, matchingResult, bucketingKey, seed, treatments, label) {
|
|
|
10
10
|
return treatments ? // Feature flag
|
|
11
11
|
{
|
|
12
12
|
treatment: (0, engineUtils_1.getTreatment)(log, bucketingKey, seed, treatments),
|
|
13
|
-
label: label
|
|
13
|
+
label: label !== null && label !== void 0 ? label : ''
|
|
14
14
|
} : // Rule-based segment
|
|
15
15
|
true;
|
|
16
16
|
}
|
|
@@ -15,7 +15,7 @@ var AbstractDefinitionsCacheSync_1 = require("../../storages/AbstractDefinitions
|
|
|
15
15
|
function pollingManagerCSFactory(params, definitionChangesFetcher) {
|
|
16
16
|
var serviceApi = params.serviceApi, storage = params.storage, readiness = params.readiness, settings = params.settings;
|
|
17
17
|
var log = settings.log;
|
|
18
|
-
var definitionsSyncTask = (0, definitionsSyncTask_1.definitionsSyncTaskFactory)(definitionChangesFetcher, storage, readiness, settings
|
|
18
|
+
var definitionsSyncTask = (0, definitionsSyncTask_1.definitionsSyncTaskFactory)(definitionChangesFetcher, storage, readiness, settings);
|
|
19
19
|
// Map of matching keys to their corresponding MySegmentsSyncTask.
|
|
20
20
|
var mySegmentsSyncTasks = {};
|
|
21
21
|
var matchingKey = (0, key_1.getMatching)(settings.core.key);
|
|
@@ -10,8 +10,8 @@ var constants_1 = require("../../logger/constants");
|
|
|
10
10
|
function pollingManagerSSFactory(params, definitionChangesFetcher, segmentChangesFetcher) {
|
|
11
11
|
var storage = params.storage, readiness = params.readiness, settings = params.settings;
|
|
12
12
|
var log = settings.log;
|
|
13
|
-
var definitionsSyncTask = (0, definitionsSyncTask_1.definitionsSyncTaskFactory)(definitionChangesFetcher, storage, readiness, settings);
|
|
14
13
|
var segmentsSyncTask = (0, segmentsSyncTask_1.segmentsSyncTaskFactory)(segmentChangesFetcher, storage, readiness, settings);
|
|
14
|
+
var definitionsSyncTask = (0, definitionsSyncTask_1.definitionsSyncTaskFactory)(definitionChangesFetcher, storage, readiness, settings, segmentsSyncTask);
|
|
15
15
|
return {
|
|
16
16
|
definitionsSyncTask: definitionsSyncTask,
|
|
17
17
|
segmentsSyncTask: segmentsSyncTask,
|
|
@@ -6,7 +6,8 @@ var definitionChangesUpdater_1 = require("../updaters/definitionChangesUpdater")
|
|
|
6
6
|
/**
|
|
7
7
|
* Creates a sync task that periodically executes a `definitionChangesUpdater` task
|
|
8
8
|
*/
|
|
9
|
-
function definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings,
|
|
10
|
-
|
|
9
|
+
function definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, segmentsSyncTask // undefined for client-side
|
|
10
|
+
) {
|
|
11
|
+
return (0, syncTask_1.syncTaskFactory)(settings.log, (0, definitionChangesUpdater_1.definitionChangesUpdaterFactory)(settings.log, definitionChangesFetcher, storage, settings.sync.__splitFiltersValidation, readiness.definitions, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, segmentsSyncTask), settings.scheduler.featuresRefreshRate, 'definitionChangesUpdater');
|
|
11
12
|
}
|
|
12
13
|
exports.definitionsSyncTaskFactory = definitionsSyncTaskFactory;
|
|
@@ -8,16 +8,6 @@ var lang_1 = require("../../../utils/lang");
|
|
|
8
8
|
var constants_3 = require("../../../utils/constants");
|
|
9
9
|
var sets_1 = require("../../../utils/lang/sets");
|
|
10
10
|
var constants_4 = require("../../streaming/constants");
|
|
11
|
-
// Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
|
|
12
|
-
// Returns a promise that could be rejected.
|
|
13
|
-
// @TODO review together with Segments and MySegments storage APIs
|
|
14
|
-
function checkAllSegmentsExist(segments) {
|
|
15
|
-
var registeredSegments = Promise.resolve(segments.getRegisteredSegments());
|
|
16
|
-
return registeredSegments.then(function (segmentNames) {
|
|
17
|
-
return Promise.all(segmentNames.map(function (segmentName) { return segments.getChangeNumber(segmentName); }))
|
|
18
|
-
.then(function (changeNumbers) { return changeNumbers.every(function (changeNumber) { return changeNumber !== undefined; }); });
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
11
|
/**
|
|
22
12
|
* Collect segments from a raw FF or RBS definition.
|
|
23
13
|
* Exported for testing purposes.
|
|
@@ -106,7 +96,8 @@ function convertInstantUpdateToDefinitionChanges(instantUpdate) {
|
|
|
106
96
|
* @param requestTimeoutBeforeReady - How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
|
|
107
97
|
* @param retriesOnFailureBeforeReady - How many retries on `/splitChanges` or `/configs` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
|
|
108
98
|
*/
|
|
109
|
-
function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage, splitFiltersValidation, definitionsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady,
|
|
99
|
+
function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage, splitFiltersValidation, definitionsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, segmentsSyncTask // undefined for client-side
|
|
100
|
+
) {
|
|
110
101
|
if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
|
|
111
102
|
if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
|
|
112
103
|
var definitions = storage.definitions, rbSegments = storage.rbSegments, segments = storage.segments;
|
|
@@ -168,8 +159,8 @@ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage,
|
|
|
168
159
|
storage.save();
|
|
169
160
|
startingUp = false;
|
|
170
161
|
if (definitionsEventEmitter) {
|
|
171
|
-
// To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must
|
|
172
|
-
return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (
|
|
162
|
+
// To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must wait for all registered segments to be fetched
|
|
163
|
+
return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (!segmentsSyncTask || segmentsSyncTask.execute(true))))
|
|
173
164
|
.catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
174
165
|
.then(function (emitSplitsArrivedEvent) {
|
|
175
166
|
// emit SDK events
|
|
@@ -66,7 +66,7 @@ function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, read
|
|
|
66
66
|
// if at least one segment fetch succeeded, mark segments ready
|
|
67
67
|
if (shouldUpdateFlags.some(function (update) { return update; }) || readyOnAlreadyExistentState) {
|
|
68
68
|
readyOnAlreadyExistentState = false;
|
|
69
|
-
if (readiness) {
|
|
69
|
+
if (readiness && !fetchOnlyNew) {
|
|
70
70
|
var metadata = {
|
|
71
71
|
type: constants_1.SEGMENTS_UPDATE,
|
|
72
72
|
names: []
|
|
@@ -11,7 +11,7 @@ var constants_5 = require("./constants");
|
|
|
11
11
|
/**
|
|
12
12
|
* DefinitionsUpdateWorker factory
|
|
13
13
|
*/
|
|
14
|
-
function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsEventEmitter, telemetryTracker
|
|
14
|
+
function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsEventEmitter, telemetryTracker) {
|
|
15
15
|
var ff = DefinitionsUpdateWorker(storage.definitions);
|
|
16
16
|
var rbs = DefinitionsUpdateWorker(storage.rbSegments);
|
|
17
17
|
function DefinitionsUpdateWorker(cache) {
|
|
@@ -35,9 +35,6 @@ function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsE
|
|
|
35
35
|
else {
|
|
36
36
|
if (instantUpdate)
|
|
37
37
|
telemetryTracker.trackUpdatesFromSSE(constants_3.SPLITS);
|
|
38
|
-
// fetch new registered segments for server-side API. Not retrying on error
|
|
39
|
-
if (segmentsSyncTask)
|
|
40
|
-
segmentsSyncTask.execute(true);
|
|
41
38
|
var attempts = backoff.attempts + 1;
|
|
42
39
|
if (ff.isSync() && rbs.isSync()) {
|
|
43
40
|
log.debug("Refresh completed".concat(cdnBypass ? ' bypassing the CDN' : '', " in ").concat(attempts, " attempts."));
|
|
@@ -46,7 +46,7 @@ function pushManagerFactory(params, pollingManager) {
|
|
|
46
46
|
// MySegmentsUpdateWorker (client-side) are initiated in `add` method
|
|
47
47
|
var segmentsUpdateWorker = userKey ? undefined : (0, SegmentsUpdateWorker_1.SegmentsUpdateWorker)(log, pollingManager.segmentsSyncTask, storage.segments);
|
|
48
48
|
// For server-side we pass the segmentsSyncTask, used by DefinitionsUpdateWorker to fetch new segments
|
|
49
|
-
var definitionsUpdateWorker = (0, DefinitionsUpdateWorker_1.DefinitionsUpdateWorker)(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker
|
|
49
|
+
var definitionsUpdateWorker = (0, DefinitionsUpdateWorker_1.DefinitionsUpdateWorker)(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker);
|
|
50
50
|
// [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
|
|
51
51
|
var userKeyHashes = {};
|
|
52
52
|
// [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
|
|
@@ -7,7 +7,7 @@ function match(log, matchingResult, bucketingKey, seed, treatments, label) {
|
|
|
7
7
|
return treatments ? // Feature flag
|
|
8
8
|
{
|
|
9
9
|
treatment: getTreatment(log, bucketingKey, seed, treatments),
|
|
10
|
-
label: label
|
|
10
|
+
label: label !== null && label !== void 0 ? label : ''
|
|
11
11
|
} : // Rule-based segment
|
|
12
12
|
true;
|
|
13
13
|
}
|
|
@@ -12,7 +12,7 @@ import { usesSegmentsSync } from '../../storages/AbstractDefinitionsCacheSync';
|
|
|
12
12
|
export function pollingManagerCSFactory(params, definitionChangesFetcher) {
|
|
13
13
|
var serviceApi = params.serviceApi, storage = params.storage, readiness = params.readiness, settings = params.settings;
|
|
14
14
|
var log = settings.log;
|
|
15
|
-
var definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings
|
|
15
|
+
var definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings);
|
|
16
16
|
// Map of matching keys to their corresponding MySegmentsSyncTask.
|
|
17
17
|
var mySegmentsSyncTasks = {};
|
|
18
18
|
var matchingKey = getMatching(settings.core.key);
|
|
@@ -7,8 +7,8 @@ import { POLLING_START, POLLING_STOP, LOG_PREFIX_SYNC_POLLING } from '../../logg
|
|
|
7
7
|
export function pollingManagerSSFactory(params, definitionChangesFetcher, segmentChangesFetcher) {
|
|
8
8
|
var storage = params.storage, readiness = params.readiness, settings = params.settings;
|
|
9
9
|
var log = settings.log;
|
|
10
|
-
var definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings);
|
|
11
10
|
var segmentsSyncTask = segmentsSyncTaskFactory(segmentChangesFetcher, storage, readiness, settings);
|
|
11
|
+
var definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, segmentsSyncTask);
|
|
12
12
|
return {
|
|
13
13
|
definitionsSyncTask: definitionsSyncTask,
|
|
14
14
|
segmentsSyncTask: segmentsSyncTask,
|
|
@@ -3,6 +3,7 @@ import { definitionChangesUpdaterFactory } from '../updaters/definitionChangesUp
|
|
|
3
3
|
/**
|
|
4
4
|
* Creates a sync task that periodically executes a `definitionChangesUpdater` task
|
|
5
5
|
*/
|
|
6
|
-
export function definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings,
|
|
7
|
-
|
|
6
|
+
export function definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, segmentsSyncTask // undefined for client-side
|
|
7
|
+
) {
|
|
8
|
+
return syncTaskFactory(settings.log, definitionChangesUpdaterFactory(settings.log, definitionChangesFetcher, storage, settings.sync.__splitFiltersValidation, readiness.definitions, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, segmentsSyncTask), settings.scheduler.featuresRefreshRate, 'definitionChangesUpdater');
|
|
8
9
|
}
|
|
@@ -5,16 +5,6 @@ import { startsWith } from '../../../utils/lang';
|
|
|
5
5
|
import { IN_RULE_BASED_SEGMENT, IN_SEGMENT, RULE_BASED_SEGMENT, STANDARD_SEGMENT } from '../../../utils/constants';
|
|
6
6
|
import { setToArray } from '../../../utils/lang/sets';
|
|
7
7
|
import { SPLIT_UPDATE } from '../../streaming/constants';
|
|
8
|
-
// Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
|
|
9
|
-
// Returns a promise that could be rejected.
|
|
10
|
-
// @TODO review together with Segments and MySegments storage APIs
|
|
11
|
-
function checkAllSegmentsExist(segments) {
|
|
12
|
-
var registeredSegments = Promise.resolve(segments.getRegisteredSegments());
|
|
13
|
-
return registeredSegments.then(function (segmentNames) {
|
|
14
|
-
return Promise.all(segmentNames.map(function (segmentName) { return segments.getChangeNumber(segmentName); }))
|
|
15
|
-
.then(function (changeNumbers) { return changeNumbers.every(function (changeNumber) { return changeNumber !== undefined; }); });
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
8
|
/**
|
|
19
9
|
* Collect segments from a raw FF or RBS definition.
|
|
20
10
|
* Exported for testing purposes.
|
|
@@ -101,7 +91,8 @@ function convertInstantUpdateToDefinitionChanges(instantUpdate) {
|
|
|
101
91
|
* @param requestTimeoutBeforeReady - How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
|
|
102
92
|
* @param retriesOnFailureBeforeReady - How many retries on `/splitChanges` or `/configs` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
|
|
103
93
|
*/
|
|
104
|
-
export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage, splitFiltersValidation, definitionsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady,
|
|
94
|
+
export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage, splitFiltersValidation, definitionsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, segmentsSyncTask // undefined for client-side
|
|
95
|
+
) {
|
|
105
96
|
if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
|
|
106
97
|
if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
|
|
107
98
|
var definitions = storage.definitions, rbSegments = storage.rbSegments, segments = storage.segments;
|
|
@@ -163,8 +154,8 @@ export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, s
|
|
|
163
154
|
storage.save();
|
|
164
155
|
startingUp = false;
|
|
165
156
|
if (definitionsEventEmitter) {
|
|
166
|
-
// To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must
|
|
167
|
-
return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (
|
|
157
|
+
// To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must wait for all registered segments to be fetched
|
|
158
|
+
return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (!segmentsSyncTask || segmentsSyncTask.execute(true))))
|
|
168
159
|
.catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
169
160
|
.then(function (emitSplitsArrivedEvent) {
|
|
170
161
|
// emit SDK events
|
|
@@ -63,7 +63,7 @@ export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segment
|
|
|
63
63
|
// if at least one segment fetch succeeded, mark segments ready
|
|
64
64
|
if (shouldUpdateFlags.some(function (update) { return update; }) || readyOnAlreadyExistentState) {
|
|
65
65
|
readyOnAlreadyExistentState = false;
|
|
66
|
-
if (readiness) {
|
|
66
|
+
if (readiness && !fetchOnlyNew) {
|
|
67
67
|
var metadata = {
|
|
68
68
|
type: SEGMENTS_UPDATE,
|
|
69
69
|
names: []
|
|
@@ -8,7 +8,7 @@ import { FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT, FETCH_BACKOFF_MAX_RETRIES }
|
|
|
8
8
|
/**
|
|
9
9
|
* DefinitionsUpdateWorker factory
|
|
10
10
|
*/
|
|
11
|
-
export function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsEventEmitter, telemetryTracker
|
|
11
|
+
export function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsEventEmitter, telemetryTracker) {
|
|
12
12
|
var ff = DefinitionsUpdateWorker(storage.definitions);
|
|
13
13
|
var rbs = DefinitionsUpdateWorker(storage.rbSegments);
|
|
14
14
|
function DefinitionsUpdateWorker(cache) {
|
|
@@ -32,9 +32,6 @@ export function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, defin
|
|
|
32
32
|
else {
|
|
33
33
|
if (instantUpdate)
|
|
34
34
|
telemetryTracker.trackUpdatesFromSSE(SPLITS);
|
|
35
|
-
// fetch new registered segments for server-side API. Not retrying on error
|
|
36
|
-
if (segmentsSyncTask)
|
|
37
|
-
segmentsSyncTask.execute(true);
|
|
38
35
|
var attempts = backoff.attempts + 1;
|
|
39
36
|
if (ff.isSync() && rbs.isSync()) {
|
|
40
37
|
log.debug("Refresh completed".concat(cdnBypass ? ' bypassing the CDN' : '', " in ").concat(attempts, " attempts."));
|
|
@@ -43,7 +43,7 @@ export function pushManagerFactory(params, pollingManager) {
|
|
|
43
43
|
// MySegmentsUpdateWorker (client-side) are initiated in `add` method
|
|
44
44
|
var segmentsUpdateWorker = userKey ? undefined : SegmentsUpdateWorker(log, pollingManager.segmentsSyncTask, storage.segments);
|
|
45
45
|
// For server-side we pass the segmentsSyncTask, used by DefinitionsUpdateWorker to fetch new segments
|
|
46
|
-
var definitionsUpdateWorker = DefinitionsUpdateWorker(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker
|
|
46
|
+
var definitionsUpdateWorker = DefinitionsUpdateWorker(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker);
|
|
47
47
|
// [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
|
|
48
48
|
var userKeyHashes = {};
|
|
49
49
|
// [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
|
package/package.json
CHANGED
package/src/dtos/types.ts
CHANGED
|
@@ -7,12 +7,12 @@ import SplitIO from '../../../types/splitio';
|
|
|
7
7
|
import { ILogger } from '../../logger/types';
|
|
8
8
|
|
|
9
9
|
// Build Evaluation object if and only if matchingResult is true
|
|
10
|
-
function match(log: ILogger, matchingResult: boolean, bucketingKey: string | undefined, seed?: number, treatments?: { getTreatmentFor: (x: number) => string }, label?: string): IEvaluation | boolean | undefined {
|
|
10
|
+
function match(log: ILogger, matchingResult: boolean, bucketingKey: string | undefined, seed?: number, treatments?: { getTreatmentFor: (x: number) => string }, label?: string | null): IEvaluation | boolean | undefined {
|
|
11
11
|
if (matchingResult) {
|
|
12
12
|
return treatments ? // Feature flag
|
|
13
13
|
{
|
|
14
14
|
treatment: getTreatment(log, bucketingKey as string, seed, treatments),
|
|
15
|
-
label: label
|
|
15
|
+
label: label ?? ''
|
|
16
16
|
} : // Rule-based segment
|
|
17
17
|
true;
|
|
18
18
|
}
|
|
@@ -22,7 +22,7 @@ function match(log: ILogger, matchingResult: boolean, bucketingKey: string | und
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
// Condition factory
|
|
25
|
-
export function conditionContext(log: ILogger, matcherEvaluator: (key: SplitIO.SplitKeyObject, attributes?: SplitIO.Attributes, splitEvaluator?: IDefinitionEvaluator) => MaybeThenable<boolean>, treatments?: { getTreatmentFor: (x: number) => string }, label?: string, conditionType?: 'ROLLOUT' | 'WHITELIST'): IEvaluator {
|
|
25
|
+
export function conditionContext(log: ILogger, matcherEvaluator: (key: SplitIO.SplitKeyObject, attributes?: SplitIO.Attributes, splitEvaluator?: IDefinitionEvaluator) => MaybeThenable<boolean>, treatments?: { getTreatmentFor: (x: number) => string }, label?: string | null, conditionType?: 'ROLLOUT' | 'WHITELIST'): IEvaluator {
|
|
26
26
|
|
|
27
27
|
return function conditionEvaluator(key: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: IDefinitionEvaluator) {
|
|
28
28
|
|
|
@@ -24,7 +24,7 @@ export function pollingManagerCSFactory(
|
|
|
24
24
|
const { serviceApi, storage, readiness, settings } = params;
|
|
25
25
|
const log = settings.log;
|
|
26
26
|
|
|
27
|
-
const definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings
|
|
27
|
+
const definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings);
|
|
28
28
|
|
|
29
29
|
// Map of matching keys to their corresponding MySegmentsSyncTask.
|
|
30
30
|
const mySegmentsSyncTasks: Record<string, IMySegmentsSyncTask> = {};
|
|
@@ -17,8 +17,8 @@ export function pollingManagerSSFactory(
|
|
|
17
17
|
const { storage, readiness, settings } = params;
|
|
18
18
|
const log = settings.log;
|
|
19
19
|
|
|
20
|
-
const definitionsSyncTask: IDefinitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings);
|
|
21
20
|
const segmentsSyncTask: ISegmentsSyncTask = segmentsSyncTaskFactory(segmentChangesFetcher, storage, readiness, settings);
|
|
21
|
+
const definitionsSyncTask: IDefinitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, segmentsSyncTask);
|
|
22
22
|
|
|
23
23
|
return {
|
|
24
24
|
definitionsSyncTask,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IStorageSync } from '../../../storages/types';
|
|
2
2
|
import { IReadinessManager } from '../../../readiness/types';
|
|
3
3
|
import { syncTaskFactory } from '../../syncTask';
|
|
4
|
-
import { IDefinitionsSyncTask } from '../types';
|
|
4
|
+
import { IDefinitionsSyncTask, ISegmentsSyncTask } from '../types';
|
|
5
5
|
import { ISettings } from '../../../types';
|
|
6
6
|
import { definitionChangesUpdaterFactory } from '../updaters/definitionChangesUpdater';
|
|
7
7
|
import { IDefinitionChangesFetcher } from '../fetchers/types';
|
|
@@ -14,7 +14,7 @@ export function definitionsSyncTaskFactory(
|
|
|
14
14
|
storage: IStorageSync,
|
|
15
15
|
readiness: IReadinessManager,
|
|
16
16
|
settings: ISettings,
|
|
17
|
-
|
|
17
|
+
segmentsSyncTask?: ISegmentsSyncTask // undefined for client-side
|
|
18
18
|
): IDefinitionsSyncTask {
|
|
19
19
|
return syncTaskFactory(
|
|
20
20
|
settings.log,
|
|
@@ -26,7 +26,7 @@ export function definitionsSyncTaskFactory(
|
|
|
26
26
|
readiness.definitions,
|
|
27
27
|
settings.startup.requestTimeoutBeforeReady,
|
|
28
28
|
settings.startup.retriesOnFailureBeforeReady,
|
|
29
|
-
|
|
29
|
+
segmentsSyncTask
|
|
30
30
|
),
|
|
31
31
|
settings.scheduler.featuresRefreshRate,
|
|
32
32
|
'definitionChangesUpdater',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IStorageBase } from '../../../storages/types';
|
|
2
2
|
import { IDefinitionChangesFetcher } from '../fetchers/types';
|
|
3
3
|
import { IRBSegment, IDefinition, IDefinitionChangesResponse, ISplitFiltersValidation, MaybeThenable } from '../../../dtos/types';
|
|
4
4
|
import { IDefinitionsEventEmitter } from '../../../readiness/types';
|
|
@@ -12,21 +12,11 @@ import { setToArray } from '../../../utils/lang/sets';
|
|
|
12
12
|
import { SPLIT_UPDATE } from '../../streaming/constants';
|
|
13
13
|
import { SdkUpdateMetadata } from '../../../../types/splitio';
|
|
14
14
|
import { ISplit } from '../fetchers/splitChangesFetcher';
|
|
15
|
+
import { ISegmentsSyncTask } from '../types';
|
|
15
16
|
|
|
16
17
|
export type InstantUpdate = { payload: ISplit | IRBSegment, changeNumber: number, type: string };
|
|
17
18
|
type DefinitionChangesUpdater = (noCache?: boolean, till?: number, instantUpdate?: InstantUpdate) => Promise<boolean>
|
|
18
19
|
|
|
19
|
-
// Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
|
|
20
|
-
// Returns a promise that could be rejected.
|
|
21
|
-
// @TODO review together with Segments and MySegments storage APIs
|
|
22
|
-
function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
|
|
23
|
-
let registeredSegments = Promise.resolve(segments.getRegisteredSegments());
|
|
24
|
-
return registeredSegments.then(segmentNames => {
|
|
25
|
-
return Promise.all(segmentNames.map(segmentName => segments.getChangeNumber(segmentName)))
|
|
26
|
-
.then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !== undefined));
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
20
|
/**
|
|
31
21
|
* Collect segments from a raw FF or RBS definition.
|
|
32
22
|
* Exported for testing purposes.
|
|
@@ -133,7 +123,7 @@ export function definitionChangesUpdaterFactory(
|
|
|
133
123
|
definitionsEventEmitter?: IDefinitionsEventEmitter,
|
|
134
124
|
requestTimeoutBeforeReady = 0,
|
|
135
125
|
retriesOnFailureBeforeReady = 0,
|
|
136
|
-
|
|
126
|
+
segmentsSyncTask?: ISegmentsSyncTask // undefined for client-side
|
|
137
127
|
): DefinitionChangesUpdater {
|
|
138
128
|
const { definitions, rbSegments, segments } = storage;
|
|
139
129
|
|
|
@@ -202,8 +192,8 @@ export function definitionChangesUpdaterFactory(
|
|
|
202
192
|
startingUp = false;
|
|
203
193
|
|
|
204
194
|
if (definitionsEventEmitter) {
|
|
205
|
-
// To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must
|
|
206
|
-
return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (
|
|
195
|
+
// To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must wait for all registered segments to be fetched
|
|
196
|
+
return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (!segmentsSyncTask || segmentsSyncTask.execute(true))))
|
|
207
197
|
.catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
208
198
|
.then(emitSplitsArrivedEvent => {
|
|
209
199
|
// emit SDK events
|
|
@@ -76,7 +76,7 @@ export function segmentChangesUpdaterFactory(
|
|
|
76
76
|
log.debug(`${LOG_PREFIX_SYNC}Started segments update`);
|
|
77
77
|
|
|
78
78
|
// If not a segment name provided, read list of available segments names to be updated.
|
|
79
|
-
|
|
79
|
+
const segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
|
|
80
80
|
|
|
81
81
|
return segmentsPromise.then(segmentNames => {
|
|
82
82
|
const updaters = segmentNames.map(segmentName => updateSegment(segmentName, noCache, till, fetchOnlyNew, readyOnAlreadyExistentState ? retriesOnFailureBeforeReady : 0));
|
|
@@ -85,7 +85,7 @@ export function segmentChangesUpdaterFactory(
|
|
|
85
85
|
// if at least one segment fetch succeeded, mark segments ready
|
|
86
86
|
if (shouldUpdateFlags.some(update => update) || readyOnAlreadyExistentState) {
|
|
87
87
|
readyOnAlreadyExistentState = false;
|
|
88
|
-
if (readiness) {
|
|
88
|
+
if (readiness && !fetchOnlyNew) {
|
|
89
89
|
const metadata: SdkUpdateMetadata = {
|
|
90
90
|
type: SEGMENTS_UPDATE,
|
|
91
91
|
names: []
|
|
@@ -7,7 +7,7 @@ import { IRBSegmentsCacheSync, IDefinitionsCacheSync, IStorageSync } from '../..
|
|
|
7
7
|
import { ITelemetryTracker } from '../../../trackers/types';
|
|
8
8
|
import { Backoff } from '../../../utils/Backoff';
|
|
9
9
|
import { SPLITS } from '../../../utils/constants';
|
|
10
|
-
import {
|
|
10
|
+
import { IDefinitionsSyncTask } from '../../polling/types';
|
|
11
11
|
import { InstantUpdate } from '../../polling/updaters/definitionChangesUpdater';
|
|
12
12
|
import { RB_SEGMENT_UPDATE } from '../constants';
|
|
13
13
|
import { parseFFUpdatePayload } from '../parseUtils';
|
|
@@ -18,7 +18,7 @@ import { IUpdateWorker } from './types';
|
|
|
18
18
|
/**
|
|
19
19
|
* DefinitionsUpdateWorker factory
|
|
20
20
|
*/
|
|
21
|
-
export function DefinitionsUpdateWorker(log: ILogger, storage: IStorageSync, definitionsSyncTask: IDefinitionsSyncTask, definitionsEventEmitter: IDefinitionsEventEmitter, telemetryTracker: ITelemetryTracker
|
|
21
|
+
export function DefinitionsUpdateWorker(log: ILogger, storage: IStorageSync, definitionsSyncTask: IDefinitionsSyncTask, definitionsEventEmitter: IDefinitionsEventEmitter, telemetryTracker: ITelemetryTracker): IUpdateWorker<[updateData: ISplitUpdateData]> & { killDefinition(event: ISplitKillData): void } {
|
|
22
22
|
|
|
23
23
|
const ff = DefinitionsUpdateWorker(storage.definitions);
|
|
24
24
|
const rbs = DefinitionsUpdateWorker(storage.rbSegments);
|
|
@@ -42,8 +42,6 @@ export function DefinitionsUpdateWorker(log: ILogger, storage: IStorageSync, def
|
|
|
42
42
|
__handleDefinitionUpdateCall();
|
|
43
43
|
} else {
|
|
44
44
|
if (instantUpdate) telemetryTracker.trackUpdatesFromSSE(SPLITS);
|
|
45
|
-
// fetch new registered segments for server-side API. Not retrying on error
|
|
46
|
-
if (segmentsSyncTask) segmentsSyncTask.execute(true);
|
|
47
45
|
|
|
48
46
|
const attempts = backoff.attempts + 1;
|
|
49
47
|
|
|
@@ -56,7 +56,7 @@ export function pushManagerFactory(
|
|
|
56
56
|
// MySegmentsUpdateWorker (client-side) are initiated in `add` method
|
|
57
57
|
const segmentsUpdateWorker = userKey ? undefined : SegmentsUpdateWorker(log, pollingManager.segmentsSyncTask as ISegmentsSyncTask, storage.segments);
|
|
58
58
|
// For server-side we pass the segmentsSyncTask, used by DefinitionsUpdateWorker to fetch new segments
|
|
59
|
-
const definitionsUpdateWorker = DefinitionsUpdateWorker(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker
|
|
59
|
+
const definitionsUpdateWorker = DefinitionsUpdateWorker(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker);
|
|
60
60
|
|
|
61
61
|
// [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
|
|
62
62
|
const userKeyHashes: Record<string, string> = {};
|