@splitsoftware/splitio-commons 2.1.0-rc.2 → 2.1.1-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +2 -7
- package/README.md +1 -0
- package/cjs/evaluator/combiners/and.js +2 -6
- package/cjs/evaluator/combiners/ifelseif.js +6 -6
- package/cjs/evaluator/condition/index.js +6 -5
- package/cjs/evaluator/index.js +7 -7
- package/cjs/evaluator/matchers/index.js +3 -1
- package/cjs/evaluator/matchers/matcherTypes.js +1 -0
- package/cjs/evaluator/matchers/rbsegment.js +43 -0
- package/cjs/evaluator/matchersTransform/index.js +4 -0
- package/cjs/evaluator/parser/index.js +2 -2
- package/cjs/evaluator/value/sanitize.js +1 -0
- package/cjs/logger/constants.js +5 -6
- package/cjs/logger/messages/debug.js +3 -4
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/readiness/readinessManager.js +0 -6
- package/cjs/services/splitApi.js +2 -2
- package/cjs/storages/AbstractSplitsCacheAsync.js +19 -1
- package/cjs/storages/AbstractSplitsCacheSync.js +17 -9
- package/cjs/storages/KeyBuilder.js +8 -15
- package/cjs/storages/KeyBuilderCS.js +11 -5
- package/cjs/storages/KeyBuilderSS.js +3 -0
- package/cjs/storages/dataLoader.js +3 -5
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +117 -0
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +69 -15
- package/cjs/storages/inLocalStorage/index.js +7 -5
- package/cjs/storages/inMemory/InMemoryStorage.js +3 -0
- package/cjs/storages/inMemory/InMemoryStorageCS.js +4 -0
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +61 -0
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +24 -31
- package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +64 -0
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +4 -21
- package/cjs/storages/inRedis/constants.js +1 -1
- package/cjs/storages/inRedis/index.js +2 -0
- package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +64 -0
- package/cjs/storages/pluggable/SplitsCachePluggable.js +2 -19
- package/cjs/storages/pluggable/index.js +3 -2
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +14 -16
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +2 -2
- package/cjs/sync/polling/pollingManagerCS.js +7 -7
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +62 -51
- package/cjs/sync/streaming/SSEHandler/index.js +1 -0
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +106 -77
- package/cjs/sync/streaming/constants.js +2 -1
- package/cjs/sync/streaming/pushManager.js +3 -16
- package/cjs/sync/syncManagerOnline.js +5 -10
- package/cjs/trackers/uniqueKeysTracker.js +1 -1
- package/cjs/utils/constants/browser.js +5 -0
- package/cjs/utils/constants/index.js +3 -2
- package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
- package/esm/evaluator/combiners/and.js +2 -6
- package/esm/evaluator/combiners/ifelseif.js +7 -7
- package/esm/evaluator/condition/index.js +6 -5
- package/esm/evaluator/index.js +7 -7
- package/esm/evaluator/matchers/index.js +3 -1
- package/esm/evaluator/matchers/matcherTypes.js +1 -0
- package/esm/evaluator/matchers/rbsegment.js +39 -0
- package/esm/evaluator/matchersTransform/index.js +4 -0
- package/esm/evaluator/parser/index.js +2 -2
- package/esm/evaluator/value/sanitize.js +1 -0
- package/esm/logger/constants.js +2 -3
- package/esm/logger/messages/debug.js +3 -4
- package/esm/logger/messages/warn.js +1 -1
- package/esm/readiness/readinessManager.js +0 -6
- package/esm/services/splitApi.js +2 -2
- package/esm/storages/AbstractSplitsCacheAsync.js +19 -1
- package/esm/storages/AbstractSplitsCacheSync.js +17 -9
- package/esm/storages/KeyBuilder.js +8 -15
- package/esm/storages/KeyBuilderCS.js +11 -5
- package/esm/storages/KeyBuilderSS.js +3 -0
- package/esm/storages/dataLoader.js +2 -4
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +114 -0
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +69 -15
- package/esm/storages/inLocalStorage/index.js +7 -5
- package/esm/storages/inMemory/InMemoryStorage.js +3 -0
- package/esm/storages/inMemory/InMemoryStorageCS.js +4 -0
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +58 -0
- package/esm/storages/inMemory/SplitsCacheInMemory.js +24 -31
- package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +61 -0
- package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -21
- package/esm/storages/inRedis/constants.js +1 -1
- package/esm/storages/inRedis/index.js +2 -0
- package/esm/storages/pluggable/RBSegmentsCachePluggable.js +61 -0
- package/esm/storages/pluggable/SplitsCachePluggable.js +2 -19
- package/esm/storages/pluggable/index.js +3 -2
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +14 -16
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +2 -2
- package/esm/sync/polling/pollingManagerCS.js +7 -7
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/esm/sync/polling/updaters/splitChangesUpdater.js +63 -52
- package/esm/sync/streaming/SSEHandler/index.js +2 -1
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +102 -73
- package/esm/sync/streaming/constants.js +1 -0
- package/esm/sync/streaming/pushManager.js +6 -19
- package/esm/sync/syncManagerOnline.js +5 -10
- package/esm/trackers/uniqueKeysTracker.js +1 -1
- package/esm/utils/constants/browser.js +2 -0
- package/esm/utils/constants/index.js +2 -1
- package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
- package/package.json +1 -1
- package/src/dtos/types.ts +32 -8
- package/src/evaluator/Engine.ts +1 -1
- package/src/evaluator/combiners/and.ts +5 -4
- package/src/evaluator/combiners/ifelseif.ts +7 -9
- package/src/evaluator/condition/engineUtils.ts +1 -1
- package/src/evaluator/condition/index.ts +12 -12
- package/src/evaluator/index.ts +7 -7
- package/src/evaluator/matchers/index.ts +3 -1
- package/src/evaluator/matchers/matcherTypes.ts +1 -0
- package/src/evaluator/matchers/rbsegment.ts +61 -0
- package/src/evaluator/matchersTransform/index.ts +3 -0
- package/src/evaluator/parser/index.ts +3 -3
- package/src/evaluator/types.ts +2 -2
- package/src/evaluator/value/index.ts +2 -2
- package/src/evaluator/value/sanitize.ts +5 -4
- package/src/logger/constants.ts +2 -3
- package/src/logger/messages/debug.ts +3 -4
- package/src/logger/messages/warn.ts +1 -1
- package/src/readiness/readinessManager.ts +0 -5
- package/src/sdkManager/index.ts +1 -1
- package/src/services/splitApi.ts +2 -2
- package/src/services/types.ts +1 -1
- package/src/storages/AbstractSplitsCacheAsync.ts +23 -5
- package/src/storages/AbstractSplitsCacheSync.ts +22 -15
- package/src/storages/KeyBuilder.ts +9 -17
- package/src/storages/KeyBuilderCS.ts +13 -6
- package/src/storages/KeyBuilderSS.ts +4 -0
- package/src/storages/dataLoader.ts +2 -5
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +136 -0
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +80 -16
- package/src/storages/inLocalStorage/index.ts +12 -8
- package/src/storages/inMemory/InMemoryStorage.ts +3 -0
- package/src/storages/inMemory/InMemoryStorageCS.ts +4 -0
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +68 -0
- package/src/storages/inMemory/SplitsCacheInMemory.ts +22 -27
- package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +79 -0
- package/src/storages/inRedis/SplitsCacheInRedis.ts +4 -21
- package/src/storages/inRedis/constants.ts +1 -1
- package/src/storages/inRedis/index.ts +2 -0
- package/src/storages/pluggable/RBSegmentsCachePluggable.ts +76 -0
- package/src/storages/pluggable/SplitsCachePluggable.ts +2 -19
- package/src/storages/pluggable/index.ts +3 -2
- package/src/storages/types.ts +47 -18
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +19 -21
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +2 -1
- package/src/sync/polling/fetchers/types.ts +1 -0
- package/src/sync/polling/pollingManagerCS.ts +7 -7
- package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -2
- package/src/sync/polling/types.ts +2 -2
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -2
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
- package/src/sync/polling/updaters/splitChangesUpdater.ts +74 -63
- package/src/sync/streaming/SSEHandler/index.ts +2 -1
- package/src/sync/streaming/SSEHandler/types.ts +2 -2
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +98 -68
- package/src/sync/streaming/constants.ts +1 -0
- package/src/sync/streaming/parseUtils.ts +2 -2
- package/src/sync/streaming/pushManager.ts +6 -18
- package/src/sync/streaming/types.ts +3 -2
- package/src/sync/syncManagerOnline.ts +5 -11
- package/src/trackers/uniqueKeysTracker.ts +1 -1
- package/src/utils/constants/browser.ts +2 -0
- package/src/utils/constants/index.ts +2 -1
- package/src/utils/lang/index.ts +2 -2
- package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
- package/types/splitio.d.ts +1 -25
- package/cjs/storages/inLocalStorage/validateCache.js +0 -79
- package/esm/storages/inLocalStorage/validateCache.js +0 -75
- package/src/storages/inLocalStorage/validateCache.ts +0 -91
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { IRBSegment } from '../../dtos/types';
|
|
2
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
3
|
+
import { usesSegments } from '../AbstractSplitsCacheSync';
|
|
4
|
+
import { IRBSegmentsCacheSync } from '../types';
|
|
5
|
+
|
|
6
|
+
export class RBSegmentsCacheInMemory implements IRBSegmentsCacheSync {
|
|
7
|
+
|
|
8
|
+
private cache: Record<string, IRBSegment> = {};
|
|
9
|
+
private changeNumber: number = -1;
|
|
10
|
+
private segmentsCount: number = 0;
|
|
11
|
+
|
|
12
|
+
clear() {
|
|
13
|
+
this.cache = {};
|
|
14
|
+
this.changeNumber = -1;
|
|
15
|
+
this.segmentsCount = 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): boolean {
|
|
19
|
+
this.changeNumber = changeNumber;
|
|
20
|
+
const updated = toAdd.map(toAdd => this.add(toAdd)).some(result => result);
|
|
21
|
+
return toRemove.map(toRemove => this.remove(toRemove.name)).some(result => result) || updated;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private add(rbSegment: IRBSegment): boolean {
|
|
25
|
+
const name = rbSegment.name;
|
|
26
|
+
const previous = this.get(name);
|
|
27
|
+
if (previous && usesSegments(previous)) this.segmentsCount--;
|
|
28
|
+
|
|
29
|
+
this.cache[name] = rbSegment;
|
|
30
|
+
if (usesSegments(rbSegment)) this.segmentsCount++;
|
|
31
|
+
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private remove(name: string): boolean {
|
|
36
|
+
const rbSegment = this.get(name);
|
|
37
|
+
if (!rbSegment) return false;
|
|
38
|
+
|
|
39
|
+
delete this.cache[name];
|
|
40
|
+
|
|
41
|
+
if (usesSegments(rbSegment)) this.segmentsCount--;
|
|
42
|
+
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private getNames(): string[] {
|
|
47
|
+
return Object.keys(this.cache);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get(name: string): IRBSegment | null {
|
|
51
|
+
return this.cache[name] || null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
contains(names: Set<string>): boolean {
|
|
55
|
+
const namesArray = setToArray(names);
|
|
56
|
+
const namesInStorage = this.getNames();
|
|
57
|
+
return namesArray.every(name => namesInStorage.indexOf(name) !== -1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getChangeNumber(): number {
|
|
61
|
+
return this.changeNumber;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
usesSegments(): boolean {
|
|
65
|
+
return this.segmentsCount > 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
}
|
|
@@ -26,7 +26,8 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
26
26
|
this.segmentsCount = 0;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
addSplit(
|
|
29
|
+
addSplit(split: ISplit): boolean {
|
|
30
|
+
const name = split.name;
|
|
30
31
|
const previousSplit = this.getSplit(name);
|
|
31
32
|
if (previousSplit) { // We had this Split already
|
|
32
33
|
|
|
@@ -40,41 +41,35 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
40
41
|
if (usesSegments(previousSplit)) this.segmentsCount--;
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
this.addToFlagSets(split);
|
|
44
|
+
// Store the Split.
|
|
45
|
+
this.splitsCache[name] = split;
|
|
46
|
+
// Update TT cache
|
|
47
|
+
const ttName = split.trafficTypeName;
|
|
48
|
+
this.ttCache[ttName] = (this.ttCache[ttName] || 0) + 1;
|
|
49
|
+
this.addToFlagSets(split);
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
// Add to segments count for the new version of the Split
|
|
52
|
+
if (usesSegments(split)) this.segmentsCount++;
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
} else {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
54
|
+
return true;
|
|
58
55
|
}
|
|
59
56
|
|
|
60
57
|
removeSplit(name: string): boolean {
|
|
61
58
|
const split = this.getSplit(name);
|
|
62
|
-
if (split)
|
|
63
|
-
// Delete the Split
|
|
64
|
-
delete this.splitsCache[name];
|
|
59
|
+
if (!split) return false;
|
|
65
60
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (!this.ttCache[ttName]) delete this.ttCache[ttName];
|
|
69
|
-
this.removeFromFlagSets(split.name, split.sets);
|
|
61
|
+
// Delete the Split
|
|
62
|
+
delete this.splitsCache[name];
|
|
70
63
|
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
const ttName = split.trafficTypeName;
|
|
65
|
+
this.ttCache[ttName]--; // Update tt cache
|
|
66
|
+
if (!this.ttCache[ttName]) delete this.ttCache[ttName];
|
|
67
|
+
this.removeFromFlagSets(split.name, split.sets);
|
|
73
68
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
// Update the segments count.
|
|
70
|
+
if (usesSegments(split)) this.segmentsCount--;
|
|
71
|
+
|
|
72
|
+
return true;
|
|
78
73
|
}
|
|
79
74
|
|
|
80
75
|
getSplit(name: string): ISplit | null {
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { isNaNNumber } from '../../utils/lang';
|
|
2
|
+
import { IRBSegmentsCacheAsync } from '../types';
|
|
3
|
+
import { ILogger } from '../../logger/types';
|
|
4
|
+
import { IRBSegment } from '../../dtos/types';
|
|
5
|
+
import { LOG_PREFIX } from './constants';
|
|
6
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
7
|
+
import { RedisAdapter } from './RedisAdapter';
|
|
8
|
+
import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
9
|
+
|
|
10
|
+
export class RBSegmentsCacheInRedis implements IRBSegmentsCacheAsync {
|
|
11
|
+
|
|
12
|
+
private readonly log: ILogger;
|
|
13
|
+
private readonly keys: KeyBuilderSS;
|
|
14
|
+
private readonly redis: RedisAdapter;
|
|
15
|
+
|
|
16
|
+
constructor(log: ILogger, keys: KeyBuilderSS, redis: RedisAdapter) {
|
|
17
|
+
this.log = log;
|
|
18
|
+
this.keys = keys;
|
|
19
|
+
this.redis = redis;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get(name: string): Promise<IRBSegment | null> {
|
|
23
|
+
return this.redis.get(this.keys.buildRBSegmentKey(name))
|
|
24
|
+
.then(maybeRBSegment => maybeRBSegment && JSON.parse(maybeRBSegment));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private getNames(): Promise<string[]> {
|
|
28
|
+
return this.redis.keys(this.keys.searchPatternForRBSegmentKeys()).then(
|
|
29
|
+
(listOfKeys) => listOfKeys.map(this.keys.extractKey)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
contains(names: Set<string>): Promise<boolean> {
|
|
34
|
+
const namesArray = setToArray(names);
|
|
35
|
+
return this.getNames().then(namesInStorage => {
|
|
36
|
+
return namesArray.every(name => namesInStorage.includes(name));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): Promise<boolean> {
|
|
41
|
+
return Promise.all([
|
|
42
|
+
this.setChangeNumber(changeNumber),
|
|
43
|
+
Promise.all(toAdd.map(toAdd => {
|
|
44
|
+
const key = this.keys.buildRBSegmentKey(toAdd.name);
|
|
45
|
+
const stringifiedNewRBSegment = JSON.stringify(toAdd);
|
|
46
|
+
return this.redis.set(key, stringifiedNewRBSegment).then(() => true);
|
|
47
|
+
})),
|
|
48
|
+
Promise.all(toRemove.map(toRemove => {
|
|
49
|
+
const key = this.keys.buildRBSegmentKey(toRemove.name);
|
|
50
|
+
return this.redis.del(key).then(status => status === 1);
|
|
51
|
+
}))
|
|
52
|
+
]).then(([, added, removed]) => {
|
|
53
|
+
return added.some(result => result) || removed.some(result => result);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
setChangeNumber(changeNumber: number) {
|
|
58
|
+
return this.redis.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '').then(
|
|
59
|
+
status => status === 'OK'
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getChangeNumber(): Promise<number> {
|
|
64
|
+
return this.redis.get(this.keys.buildRBSegmentsTillKey()).then((value: string | null) => {
|
|
65
|
+
const i = parseInt(value as string, 10);
|
|
66
|
+
|
|
67
|
+
return isNaNNumber(i) ? -1 : i;
|
|
68
|
+
}).catch((e) => {
|
|
69
|
+
this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from storage. Error: ' + e);
|
|
70
|
+
return -1;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// @TODO implement if required by DataLoader or producer mode
|
|
75
|
+
clear() {
|
|
76
|
+
return Promise.resolve();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|
|
@@ -82,7 +82,8 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
82
82
|
* The returned promise is resolved when the operation success
|
|
83
83
|
* or rejected if it fails (e.g., redis operation fails)
|
|
84
84
|
*/
|
|
85
|
-
addSplit(
|
|
85
|
+
addSplit(split: ISplit): Promise<boolean> {
|
|
86
|
+
const name = split.name;
|
|
86
87
|
const splitKey = this.keys.buildSplitKey(name);
|
|
87
88
|
return this.redis.get(splitKey).then(splitFromStorage => {
|
|
88
89
|
|
|
@@ -107,18 +108,9 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
107
108
|
}).then(() => true);
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
/**
|
|
111
|
-
* Add a list of splits.
|
|
112
|
-
* The returned promise is resolved when the operation success
|
|
113
|
-
* or rejected if it fails (e.g., redis operation fails)
|
|
114
|
-
*/
|
|
115
|
-
addSplits(entries: [string, ISplit][]): Promise<boolean[]> {
|
|
116
|
-
return Promise.all(entries.map(keyValuePair => this.addSplit(keyValuePair[0], keyValuePair[1])));
|
|
117
|
-
}
|
|
118
|
-
|
|
119
111
|
/**
|
|
120
112
|
* Remove a given split.
|
|
121
|
-
* The returned promise is resolved when the operation success, with
|
|
113
|
+
* The returned promise is resolved when the operation success, with true or false indicating if the split existed (and was removed) or not.
|
|
122
114
|
* or rejected if it fails (e.g., redis operation fails).
|
|
123
115
|
*/
|
|
124
116
|
removeSplit(name: string) {
|
|
@@ -127,19 +119,10 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
127
119
|
return this._decrementCounts(split).then(() => this._updateFlagSets(name, split.sets));
|
|
128
120
|
}
|
|
129
121
|
}).then(() => {
|
|
130
|
-
return this.redis.del(this.keys.buildSplitKey(name));
|
|
122
|
+
return this.redis.del(this.keys.buildSplitKey(name)).then(status => status === 1);
|
|
131
123
|
});
|
|
132
124
|
}
|
|
133
125
|
|
|
134
|
-
/**
|
|
135
|
-
* Remove a list of splits.
|
|
136
|
-
* The returned promise is resolved when the operation success,
|
|
137
|
-
* or rejected if it fails (e.g., redis operation fails).
|
|
138
|
-
*/
|
|
139
|
-
removeSplits(names: string[]): Promise<any> {
|
|
140
|
-
return Promise.all(names.map(name => this.removeSplit(name)));
|
|
141
|
-
}
|
|
142
|
-
|
|
143
126
|
/**
|
|
144
127
|
* Get split definition or null if it's not defined.
|
|
145
128
|
* Returned promise is rejected if redis operation fails.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export const LOG_PREFIX = 'storage:redis: ';
|
|
2
2
|
export const DEFAULT_CACHE_SIZE = 30000;
|
|
3
|
-
export const REFRESH_RATE = 300000; //
|
|
3
|
+
export const REFRESH_RATE = 300000; // 300000 ms = start after 5 mins
|
|
4
4
|
export const TTL_REFRESH = 3600; // 1hr
|
|
@@ -11,6 +11,7 @@ import { TelemetryCacheInRedis } from './TelemetryCacheInRedis';
|
|
|
11
11
|
import { UniqueKeysCacheInRedis } from './UniqueKeysCacheInRedis';
|
|
12
12
|
import { ImpressionCountsCacheInRedis } from './ImpressionCountsCacheInRedis';
|
|
13
13
|
import { metadataBuilder } from '../utils';
|
|
14
|
+
import { RBSegmentsCacheInRedis } from './RBSegmentsCacheInRedis';
|
|
14
15
|
|
|
15
16
|
export interface InRedisStorageOptions {
|
|
16
17
|
prefix?: string
|
|
@@ -50,6 +51,7 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
|
|
|
50
51
|
|
|
51
52
|
return {
|
|
52
53
|
splits: new SplitsCacheInRedis(log, keys, redisClient, settings.sync.__splitFiltersValidation),
|
|
54
|
+
rbSegments: new RBSegmentsCacheInRedis(log, keys, redisClient),
|
|
53
55
|
segments: new SegmentsCacheInRedis(log, keys, redisClient),
|
|
54
56
|
impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
|
|
55
57
|
impressionCounts: impressionCountsCache,
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { isNaNNumber } from '../../utils/lang';
|
|
2
|
+
import { KeyBuilder } from '../KeyBuilder';
|
|
3
|
+
import { IPluggableStorageWrapper, IRBSegmentsCacheAsync } from '../types';
|
|
4
|
+
import { ILogger } from '../../logger/types';
|
|
5
|
+
import { IRBSegment } from '../../dtos/types';
|
|
6
|
+
import { LOG_PREFIX } from './constants';
|
|
7
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
8
|
+
|
|
9
|
+
export class RBSegmentsCachePluggable implements IRBSegmentsCacheAsync {
|
|
10
|
+
|
|
11
|
+
private readonly log: ILogger;
|
|
12
|
+
private readonly keys: KeyBuilder;
|
|
13
|
+
private readonly wrapper: IPluggableStorageWrapper;
|
|
14
|
+
|
|
15
|
+
constructor(log: ILogger, keys: KeyBuilder, wrapper: IPluggableStorageWrapper) {
|
|
16
|
+
this.log = log;
|
|
17
|
+
this.keys = keys;
|
|
18
|
+
this.wrapper = wrapper;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get(name: string): Promise<IRBSegment | null> {
|
|
22
|
+
return this.wrapper.get(this.keys.buildRBSegmentKey(name))
|
|
23
|
+
.then(maybeRBSegment => maybeRBSegment && JSON.parse(maybeRBSegment));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private getNames(): Promise<string[]> {
|
|
27
|
+
return this.wrapper.getKeysByPrefix(this.keys.buildRBSegmentKeyPrefix()).then(
|
|
28
|
+
(listOfKeys) => listOfKeys.map(this.keys.extractKey)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
contains(names: Set<string>): Promise<boolean> {
|
|
33
|
+
const namesArray = setToArray(names);
|
|
34
|
+
return this.getNames().then(namesInStorage => {
|
|
35
|
+
return namesArray.every(name => namesInStorage.includes(name));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): Promise<boolean> {
|
|
40
|
+
return Promise.all([
|
|
41
|
+
this.setChangeNumber(changeNumber),
|
|
42
|
+
Promise.all(toAdd.map(toAdd => {
|
|
43
|
+
const key = this.keys.buildRBSegmentKey(toAdd.name);
|
|
44
|
+
const stringifiedNewRBSegment = JSON.stringify(toAdd);
|
|
45
|
+
return this.wrapper.set(key, stringifiedNewRBSegment).then(() => true);
|
|
46
|
+
})),
|
|
47
|
+
Promise.all(toRemove.map(toRemove => {
|
|
48
|
+
const key = this.keys.buildRBSegmentKey(toRemove.name);
|
|
49
|
+
return this.wrapper.del(key);
|
|
50
|
+
}))
|
|
51
|
+
]).then(([, added, removed]) => {
|
|
52
|
+
return added.some(result => result) || removed.some(result => result);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
setChangeNumber(changeNumber: number) {
|
|
57
|
+
return this.wrapper.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getChangeNumber(): Promise<number> {
|
|
61
|
+
return this.wrapper.get(this.keys.buildRBSegmentsTillKey()).then((value) => {
|
|
62
|
+
const i = parseInt(value as string, 10);
|
|
63
|
+
|
|
64
|
+
return isNaNNumber(i) ? -1 : i;
|
|
65
|
+
}).catch((e) => {
|
|
66
|
+
this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from storage. Error: ' + e);
|
|
67
|
+
return -1;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// @TODO implement if required by DataLoader or producer mode
|
|
72
|
+
clear() {
|
|
73
|
+
return Promise.resolve();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
}
|
|
@@ -66,7 +66,8 @@ export class SplitsCachePluggable extends AbstractSplitsCacheAsync {
|
|
|
66
66
|
* The returned promise is resolved when the operation success
|
|
67
67
|
* or rejected if it fails (e.g., wrapper operation fails)
|
|
68
68
|
*/
|
|
69
|
-
addSplit(
|
|
69
|
+
addSplit(split: ISplit): Promise<boolean> {
|
|
70
|
+
const name = split.name;
|
|
70
71
|
const splitKey = this.keys.buildSplitKey(name);
|
|
71
72
|
return this.wrapper.get(splitKey).then(splitFromStorage => {
|
|
72
73
|
|
|
@@ -91,15 +92,6 @@ export class SplitsCachePluggable extends AbstractSplitsCacheAsync {
|
|
|
91
92
|
}).then(() => true);
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
/**
|
|
95
|
-
* Add a list of splits.
|
|
96
|
-
* The returned promise is resolved when the operation success
|
|
97
|
-
* or rejected if it fails (e.g., wrapper operation fails)
|
|
98
|
-
*/
|
|
99
|
-
addSplits(entries: [string, ISplit][]): Promise<boolean[]> {
|
|
100
|
-
return Promise.all(entries.map(keyValuePair => this.addSplit(keyValuePair[0], keyValuePair[1])));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
95
|
/**
|
|
104
96
|
* Remove a given split.
|
|
105
97
|
* The returned promise is resolved when the operation success, with a boolean indicating if the split existed or not.
|
|
@@ -115,15 +107,6 @@ export class SplitsCachePluggable extends AbstractSplitsCacheAsync {
|
|
|
115
107
|
});
|
|
116
108
|
}
|
|
117
109
|
|
|
118
|
-
/**
|
|
119
|
-
* Remove a list of splits.
|
|
120
|
-
* The returned promise is resolved when the operation success, with a boolean array indicating if the splits existed or not.
|
|
121
|
-
* or rejected if it fails (e.g., wrapper operation fails).
|
|
122
|
-
*/
|
|
123
|
-
removeSplits(names: string[]): Promise<void> { // @ts-ignore
|
|
124
|
-
return Promise.all(names.map(name => this.removeSplit(name)));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
110
|
/**
|
|
128
111
|
* Get split.
|
|
129
112
|
* The returned promise is resolved with the split definition or null if it's not defined,
|
|
@@ -20,6 +20,7 @@ import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
|
|
|
20
20
|
import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
|
|
21
21
|
import { metadataBuilder } from '../utils';
|
|
22
22
|
import { LOG_PREFIX } from '../pluggable/constants';
|
|
23
|
+
import { RBSegmentsCachePluggable } from './RBSegmentsCachePluggable';
|
|
23
24
|
|
|
24
25
|
const NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.';
|
|
25
26
|
const NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.';
|
|
@@ -88,8 +89,7 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
88
89
|
// Connects to wrapper and emits SDK_READY event on main client
|
|
89
90
|
const connectPromise = wrapper.connect().then(() => {
|
|
90
91
|
if (isSynchronizer) {
|
|
91
|
-
//
|
|
92
|
-
// In standalone or producer mode, clear storage if SDK key, flags filter criteria or flags spec version was modified
|
|
92
|
+
// In standalone or producer mode, clear storage if SDK key or feature flag filter has changed
|
|
93
93
|
return wrapper.get(keys.buildHashKey()).then((hash) => {
|
|
94
94
|
const currentHash = getStorageHash(settings);
|
|
95
95
|
if (hash !== currentHash) {
|
|
@@ -117,6 +117,7 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
117
117
|
|
|
118
118
|
return {
|
|
119
119
|
splits: new SplitsCachePluggable(log, keys, wrapper, settings.sync.__splitFiltersValidation),
|
|
120
|
+
rbSegments: new RBSegmentsCachePluggable(log, keys, wrapper),
|
|
120
121
|
segments: new SegmentsCachePluggable(log, keys, wrapper),
|
|
121
122
|
impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
|
|
122
123
|
impressionCounts: impressionCountsCache,
|
package/src/storages/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import SplitIO from '../../types/splitio';
|
|
2
|
-
import { MaybeThenable, ISplit, IMySegmentsResponse } from '../dtos/types';
|
|
2
|
+
import { MaybeThenable, ISplit, IRBSegment, IMySegmentsResponse } from '../dtos/types';
|
|
3
3
|
import { MySegmentsData } from '../sync/polling/types';
|
|
4
4
|
import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, MultiMethodExceptions, MultiMethodLatencies, MultiConfigs, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent, UniqueKeysPayloadCs, UniqueKeysPayloadSs, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../sync/submitters/types';
|
|
5
5
|
import { ISettings } from '../types';
|
|
@@ -177,11 +177,9 @@ export interface IPluggableStorageWrapper {
|
|
|
177
177
|
/** Splits cache */
|
|
178
178
|
|
|
179
179
|
export interface ISplitsCacheBase {
|
|
180
|
-
|
|
181
|
-
removeSplits(names: string[]): MaybeThenable<boolean[] | void>,
|
|
180
|
+
update(toAdd: ISplit[], toRemove: ISplit[], changeNumber: number): MaybeThenable<boolean>,
|
|
182
181
|
getSplit(name: string): MaybeThenable<ISplit | null>,
|
|
183
182
|
getSplits(names: string[]): MaybeThenable<Record<string, ISplit | null>>, // `fetchMany` in spec
|
|
184
|
-
setChangeNumber(changeNumber: number): MaybeThenable<boolean | void>,
|
|
185
183
|
// should never reject or throw an exception. Instead return -1 by default, assuming no splits are present in the storage.
|
|
186
184
|
getChangeNumber(): MaybeThenable<number>,
|
|
187
185
|
getAll(): MaybeThenable<ISplit[]>,
|
|
@@ -191,42 +189,70 @@ export interface ISplitsCacheBase {
|
|
|
191
189
|
// only for Client-Side. Returns true if the storage is not synchronized yet (getChangeNumber() === -1) or contains a FF using segments or large segments
|
|
192
190
|
usesSegments(): MaybeThenable<boolean>,
|
|
193
191
|
clear(): MaybeThenable<boolean | void>,
|
|
192
|
+
// should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE.
|
|
193
|
+
checkCache(): MaybeThenable<boolean>,
|
|
194
194
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): MaybeThenable<boolean>,
|
|
195
195
|
getNamesByFlagSets(flagSets: string[]): MaybeThenable<Set<string>[]>
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
export interface ISplitsCacheSync extends ISplitsCacheBase {
|
|
199
|
-
|
|
200
|
-
removeSplits(names: string[]): boolean[],
|
|
199
|
+
update(toAdd: ISplit[], toRemove: ISplit[], changeNumber: number): boolean,
|
|
201
200
|
getSplit(name: string): ISplit | null,
|
|
202
201
|
getSplits(names: string[]): Record<string, ISplit | null>,
|
|
203
|
-
setChangeNumber(changeNumber: number): boolean | void,
|
|
204
202
|
getChangeNumber(): number,
|
|
205
203
|
getAll(): ISplit[],
|
|
206
204
|
getSplitNames(): string[],
|
|
207
205
|
trafficTypeExists(trafficType: string): boolean,
|
|
208
206
|
usesSegments(): boolean,
|
|
209
207
|
clear(): void,
|
|
208
|
+
checkCache(): boolean,
|
|
210
209
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean,
|
|
211
210
|
getNamesByFlagSets(flagSets: string[]): Set<string>[]
|
|
212
211
|
}
|
|
213
212
|
|
|
214
213
|
export interface ISplitsCacheAsync extends ISplitsCacheBase {
|
|
215
|
-
|
|
216
|
-
removeSplits(names: string[]): Promise<boolean[] | void>,
|
|
214
|
+
update(toAdd: ISplit[], toRemove: ISplit[], changeNumber: number): Promise<boolean>,
|
|
217
215
|
getSplit(name: string): Promise<ISplit | null>,
|
|
218
216
|
getSplits(names: string[]): Promise<Record<string, ISplit | null>>,
|
|
219
|
-
setChangeNumber(changeNumber: number): Promise<boolean | void>,
|
|
220
217
|
getChangeNumber(): Promise<number>,
|
|
221
218
|
getAll(): Promise<ISplit[]>,
|
|
222
219
|
getSplitNames(): Promise<string[]>,
|
|
223
220
|
trafficTypeExists(trafficType: string): Promise<boolean>,
|
|
224
221
|
usesSegments(): Promise<boolean>,
|
|
225
222
|
clear(): Promise<boolean | void>,
|
|
223
|
+
checkCache(): Promise<boolean>,
|
|
226
224
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise<boolean>,
|
|
227
225
|
getNamesByFlagSets(flagSets: string[]): Promise<Set<string>[]>
|
|
228
226
|
}
|
|
229
227
|
|
|
228
|
+
/** Rule-Based Segments cache */
|
|
229
|
+
|
|
230
|
+
export interface IRBSegmentsCacheBase {
|
|
231
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): MaybeThenable<boolean>,
|
|
232
|
+
get(name: string): MaybeThenable<IRBSegment | null>,
|
|
233
|
+
getChangeNumber(): MaybeThenable<number>,
|
|
234
|
+
clear(): MaybeThenable<boolean | void>,
|
|
235
|
+
contains(names: Set<string>): MaybeThenable<boolean>,
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export interface IRBSegmentsCacheSync extends IRBSegmentsCacheBase {
|
|
239
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): boolean,
|
|
240
|
+
get(name: string): IRBSegment | null,
|
|
241
|
+
getChangeNumber(): number,
|
|
242
|
+
clear(): void,
|
|
243
|
+
contains(names: Set<string>): boolean,
|
|
244
|
+
// Used only for smart pausing in client-side standalone. Returns true if the storage contains a RBSegment using segments or large segments matchers
|
|
245
|
+
usesSegments(): boolean,
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export interface IRBSegmentsCacheAsync extends IRBSegmentsCacheBase {
|
|
249
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): Promise<boolean>,
|
|
250
|
+
get(name: string): Promise<IRBSegment | null>,
|
|
251
|
+
getChangeNumber(): Promise<number>,
|
|
252
|
+
clear(): Promise<boolean | void>,
|
|
253
|
+
contains(names: Set<string>): Promise<boolean>,
|
|
254
|
+
}
|
|
255
|
+
|
|
230
256
|
/** Segments cache */
|
|
231
257
|
|
|
232
258
|
export interface ISegmentsCacheBase {
|
|
@@ -424,15 +450,17 @@ export interface ITelemetryCacheAsync extends ITelemetryEvaluationProducerAsync,
|
|
|
424
450
|
*/
|
|
425
451
|
|
|
426
452
|
export interface IStorageBase<
|
|
427
|
-
TSplitsCache extends ISplitsCacheBase,
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
453
|
+
TSplitsCache extends ISplitsCacheBase = ISplitsCacheBase,
|
|
454
|
+
TRBSegmentsCache extends IRBSegmentsCacheBase = IRBSegmentsCacheBase,
|
|
455
|
+
TSegmentsCache extends ISegmentsCacheBase = ISegmentsCacheBase,
|
|
456
|
+
TImpressionsCache extends IImpressionsCacheBase = IImpressionsCacheBase,
|
|
457
|
+
TImpressionsCountCache extends IImpressionCountsCacheBase = IImpressionCountsCacheBase,
|
|
458
|
+
TEventsCache extends IEventsCacheBase = IEventsCacheBase,
|
|
459
|
+
TTelemetryCache extends ITelemetryCacheSync | ITelemetryCacheAsync = ITelemetryCacheSync | ITelemetryCacheAsync,
|
|
460
|
+
TUniqueKeysCache extends IUniqueKeysCacheBase = IUniqueKeysCacheBase
|
|
434
461
|
> {
|
|
435
462
|
splits: TSplitsCache,
|
|
463
|
+
rbSegments: TRBSegmentsCache,
|
|
436
464
|
segments: TSegmentsCache,
|
|
437
465
|
impressions: TImpressionsCache,
|
|
438
466
|
impressionCounts: TImpressionsCountCache,
|
|
@@ -445,6 +473,7 @@ export interface IStorageBase<
|
|
|
445
473
|
|
|
446
474
|
export interface IStorageSync extends IStorageBase<
|
|
447
475
|
ISplitsCacheSync,
|
|
476
|
+
IRBSegmentsCacheSync,
|
|
448
477
|
ISegmentsCacheSync,
|
|
449
478
|
IImpressionsCacheSync,
|
|
450
479
|
IImpressionCountsCacheSync,
|
|
@@ -453,12 +482,12 @@ export interface IStorageSync extends IStorageBase<
|
|
|
453
482
|
IUniqueKeysCacheSync
|
|
454
483
|
> {
|
|
455
484
|
// Defined in client-side
|
|
456
|
-
validateCache?: () => boolean, // @TODO support async
|
|
457
485
|
largeSegments?: ISegmentsCacheSync,
|
|
458
486
|
}
|
|
459
487
|
|
|
460
488
|
export interface IStorageAsync extends IStorageBase<
|
|
461
489
|
ISplitsCacheAsync,
|
|
490
|
+
IRBSegmentsCacheAsync,
|
|
462
491
|
ISegmentsCacheAsync,
|
|
463
492
|
IImpressionsCacheAsync | IImpressionsCacheSync,
|
|
464
493
|
IImpressionCountsCacheBase,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { forOwn } from '../../../utils/lang';
|
|
2
2
|
import { IReadinessManager } from '../../../readiness/types';
|
|
3
|
-
import {
|
|
3
|
+
import { ISplitsCacheSync } from '../../../storages/types';
|
|
4
4
|
import { ISplitsParser } from '../splitsParser/types';
|
|
5
5
|
import { ISplit, ISplitPartial } from '../../../dtos/types';
|
|
6
6
|
import { syncTaskFactory } from '../../syncTask';
|
|
@@ -15,7 +15,7 @@ import { SYNC_OFFLINE_DATA, ERROR_SYNC_OFFLINE_LOADING } from '../../../logger/c
|
|
|
15
15
|
*/
|
|
16
16
|
export function fromObjectUpdaterFactory(
|
|
17
17
|
splitsParser: ISplitsParser,
|
|
18
|
-
storage:
|
|
18
|
+
storage: { splits: ISplitsCacheSync },
|
|
19
19
|
readiness: IReadinessManager,
|
|
20
20
|
settings: ISettings,
|
|
21
21
|
): () => Promise<boolean> {
|
|
@@ -24,7 +24,7 @@ export function fromObjectUpdaterFactory(
|
|
|
24
24
|
let startingUp = true;
|
|
25
25
|
|
|
26
26
|
return function objectUpdater() {
|
|
27
|
-
const splits:
|
|
27
|
+
const splits: ISplit[] = [];
|
|
28
28
|
let loadError = null;
|
|
29
29
|
let splitsMock: false | Record<string, ISplitPartial> = {};
|
|
30
30
|
try {
|
|
@@ -37,33 +37,31 @@ export function fromObjectUpdaterFactory(
|
|
|
37
37
|
if (!loadError && splitsMock) {
|
|
38
38
|
log.debug(SYNC_OFFLINE_DATA, [JSON.stringify(splitsMock)]);
|
|
39
39
|
|
|
40
|
-
forOwn(splitsMock,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
]);
|
|
40
|
+
forOwn(splitsMock, (val, name) => {
|
|
41
|
+
// @ts-ignore Split changeNumber and seed is undefined in localhost mode
|
|
42
|
+
splits.push({
|
|
43
|
+
name,
|
|
44
|
+
status: 'ACTIVE',
|
|
45
|
+
killed: false,
|
|
46
|
+
trafficAllocation: 100,
|
|
47
|
+
defaultTreatment: CONTROL,
|
|
48
|
+
conditions: val.conditions || [],
|
|
49
|
+
configurations: val.configurations,
|
|
50
|
+
trafficTypeName: val.trafficTypeName
|
|
51
|
+
});
|
|
53
52
|
});
|
|
54
53
|
|
|
55
54
|
return Promise.all([
|
|
56
55
|
splitsCache.clear(), // required to sync removed splits from mock
|
|
57
|
-
splitsCache.
|
|
56
|
+
splitsCache.update(splits, [], Date.now())
|
|
58
57
|
]).then(() => {
|
|
59
58
|
readiness.splits.emit(SDK_SPLITS_ARRIVED);
|
|
60
59
|
|
|
61
60
|
if (startingUp) {
|
|
62
61
|
startingUp = false;
|
|
63
|
-
|
|
64
|
-
Promise.resolve().then(() => {
|
|
62
|
+
Promise.resolve(splitsCache.checkCache()).then(cacheReady => {
|
|
65
63
|
// Emits SDK_READY_FROM_CACHE
|
|
66
|
-
if (
|
|
64
|
+
if (cacheReady) readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
|
|
67
65
|
// Emits SDK_READY
|
|
68
66
|
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
69
67
|
});
|
|
@@ -81,7 +79,7 @@ export function fromObjectUpdaterFactory(
|
|
|
81
79
|
*/
|
|
82
80
|
export function fromObjectSyncTaskFactory(
|
|
83
81
|
splitsParser: ISplitsParser,
|
|
84
|
-
storage:
|
|
82
|
+
storage: { splits: ISplitsCacheSync },
|
|
85
83
|
readiness: IReadinessManager,
|
|
86
84
|
settings: ISettings
|
|
87
85
|
): ISyncTask<[], boolean> {
|