@splitsoftware/splitio-commons 1.17.1-rc.2 → 2.0.0-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 +7 -3
- package/cjs/evaluator/index.js +2 -2
- package/cjs/evaluator/matchers/semver_inlist.js +1 -2
- package/cjs/evaluator/matchers/whitelist.js +1 -2
- package/cjs/listeners/browser.js +1 -2
- package/cjs/logger/browser/DebugLogger.js +1 -2
- package/cjs/logger/browser/ErrorLogger.js +1 -2
- package/cjs/logger/browser/InfoLogger.js +1 -2
- package/cjs/logger/browser/WarnLogger.js +1 -2
- package/cjs/logger/index.js +1 -2
- package/cjs/sdkClient/clientCS.js +5 -8
- package/cjs/sdkClient/sdkClientMethodCS.js +1 -1
- package/cjs/sdkFactory/index.js +1 -3
- package/cjs/services/decorateHeaders.js +1 -2
- package/cjs/storages/AbstractSplitsCacheAsync.js +7 -0
- package/cjs/storages/AbstractSplitsCacheSync.js +7 -0
- package/cjs/storages/KeyBuilderCS.js +0 -9
- package/cjs/storages/dataLoader.js +32 -65
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -21
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +14 -7
- package/cjs/storages/inLocalStorage/index.js +1 -4
- package/cjs/storages/inMemory/InMemoryStorageCS.js +4 -16
- package/cjs/storages/inMemory/SegmentsCacheInMemory.js +3 -4
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +2 -3
- package/cjs/storages/inMemory/UniqueKeysCacheInMemory.js +2 -3
- package/cjs/storages/inMemory/UniqueKeysCacheInMemoryCS.js +2 -3
- package/cjs/storages/inRedis/RedisAdapter.js +2 -3
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/TelemetryCacheInRedis.js +3 -4
- package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +1 -2
- package/cjs/storages/pluggable/SplitsCachePluggable.js +1 -1
- package/cjs/storages/pluggable/TelemetryCachePluggable.js +6 -7
- package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +1 -2
- package/cjs/storages/pluggable/inMemoryWrapper.js +7 -8
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +7 -2
- package/cjs/sync/polling/pollingManagerSS.js +3 -3
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +13 -5
- package/cjs/sync/streaming/parseUtils.js +0 -1
- package/cjs/sync/streaming/pushManager.js +2 -3
- package/cjs/utils/LRUCache/index.js +1 -2
- package/cjs/utils/constants/browser.js +1 -4
- package/cjs/utils/lang/index.js +6 -9
- package/cjs/utils/lang/objectAssign.js +12 -77
- package/cjs/utils/lang/sets.js +3 -110
- package/cjs/utils/settingsValidation/index.js +0 -9
- package/cjs/utils/settingsValidation/logger/builtinLogger.js +1 -2
- package/cjs/utils/settingsValidation/storage/storageCS.js +12 -1
- package/esm/evaluator/index.js +3 -3
- package/esm/evaluator/matchers/semver_inlist.js +1 -2
- package/esm/evaluator/matchers/whitelist.js +1 -2
- package/esm/listeners/browser.js +1 -2
- package/esm/logger/browser/DebugLogger.js +1 -2
- package/esm/logger/browser/ErrorLogger.js +1 -2
- package/esm/logger/browser/InfoLogger.js +1 -2
- package/esm/logger/browser/WarnLogger.js +1 -2
- package/esm/logger/index.js +1 -2
- package/esm/sdkClient/clientCS.js +5 -8
- package/esm/sdkClient/sdkClientMethodCS.js +1 -1
- package/esm/sdkFactory/index.js +2 -4
- package/esm/services/decorateHeaders.js +1 -2
- package/esm/storages/AbstractSplitsCacheAsync.js +7 -0
- package/esm/storages/AbstractSplitsCacheSync.js +7 -0
- package/esm/storages/KeyBuilderCS.js +0 -9
- package/esm/storages/dataLoader.js +30 -62
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +1 -21
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +14 -7
- package/esm/storages/inLocalStorage/index.js +2 -5
- package/esm/storages/inMemory/InMemoryStorageCS.js +4 -16
- package/esm/storages/inMemory/SegmentsCacheInMemory.js +3 -4
- package/esm/storages/inMemory/SplitsCacheInMemory.js +2 -3
- package/esm/storages/inMemory/UniqueKeysCacheInMemory.js +2 -3
- package/esm/storages/inMemory/UniqueKeysCacheInMemoryCS.js +2 -3
- package/esm/storages/inRedis/RedisAdapter.js +2 -3
- package/esm/storages/inRedis/SplitsCacheInRedis.js +2 -2
- package/esm/storages/inRedis/TelemetryCacheInRedis.js +3 -4
- package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +1 -2
- package/esm/storages/pluggable/SplitsCachePluggable.js +2 -2
- package/esm/storages/pluggable/TelemetryCachePluggable.js +6 -7
- package/esm/storages/pluggable/UniqueKeysCachePluggable.js +1 -2
- package/esm/storages/pluggable/inMemoryWrapper.js +7 -8
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +8 -3
- package/esm/sync/polling/pollingManagerSS.js +3 -3
- package/esm/sync/polling/updaters/splitChangesUpdater.js +14 -6
- package/esm/sync/streaming/parseUtils.js +0 -1
- package/esm/sync/streaming/pushManager.js +2 -3
- package/esm/utils/LRUCache/index.js +1 -2
- package/esm/utils/constants/browser.js +0 -3
- package/esm/utils/lang/index.js +6 -9
- package/esm/utils/lang/objectAssign.js +12 -77
- package/esm/utils/lang/sets.js +2 -107
- package/esm/utils/settingsValidation/index.js +0 -9
- package/esm/utils/settingsValidation/logger/builtinLogger.js +1 -2
- package/esm/utils/settingsValidation/storage/storageCS.js +10 -0
- package/package.json +2 -2
- package/src/evaluator/index.ts +5 -5
- package/src/evaluator/matchers/semver_inlist.ts +1 -2
- package/src/evaluator/matchers/whitelist.ts +1 -3
- package/src/listeners/browser.ts +1 -2
- package/src/logger/browser/DebugLogger.ts +1 -2
- package/src/logger/browser/ErrorLogger.ts +1 -2
- package/src/logger/browser/InfoLogger.ts +1 -2
- package/src/logger/browser/WarnLogger.ts +1 -2
- package/src/logger/index.ts +3 -4
- package/src/sdkClient/clientCS.ts +5 -8
- package/src/sdkClient/sdkClientMethodCS.ts +1 -1
- package/src/sdkFactory/index.ts +2 -5
- package/src/sdkFactory/types.ts +1 -1
- package/src/services/decorateHeaders.ts +1 -2
- package/src/storages/AbstractSplitsCacheAsync.ts +9 -2
- package/src/storages/AbstractSplitsCacheSync.ts +9 -2
- package/src/storages/KeyBuilderCS.ts +0 -13
- package/src/storages/dataLoader.ts +32 -63
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +1 -21
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +16 -8
- package/src/storages/inLocalStorage/index.ts +2 -6
- package/src/storages/inMemory/InMemoryStorageCS.ts +4 -19
- package/src/storages/inMemory/SegmentsCacheInMemory.ts +4 -5
- package/src/storages/inMemory/SplitsCacheInMemory.ts +4 -5
- package/src/storages/inMemory/UniqueKeysCacheInMemory.ts +4 -5
- package/src/storages/inMemory/UniqueKeysCacheInMemoryCS.ts +4 -5
- package/src/storages/inRedis/RedisAdapter.ts +3 -4
- package/src/storages/inRedis/SplitsCacheInRedis.ts +3 -3
- package/src/storages/inRedis/TelemetryCacheInRedis.ts +3 -4
- package/src/storages/inRedis/UniqueKeysCacheInRedis.ts +1 -2
- package/src/storages/pluggable/SegmentsCachePluggable.ts +0 -1
- package/src/storages/pluggable/SplitsCachePluggable.ts +3 -3
- package/src/storages/pluggable/TelemetryCachePluggable.ts +6 -7
- package/src/storages/pluggable/UniqueKeysCachePluggable.ts +1 -2
- package/src/storages/pluggable/inMemoryWrapper.ts +8 -9
- package/src/storages/types.ts +9 -5
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +7 -3
- package/src/sync/polling/pollingManagerSS.ts +2 -3
- package/src/sync/polling/updaters/splitChangesUpdater.ts +15 -8
- package/src/sync/streaming/parseUtils.ts +0 -1
- package/src/sync/streaming/pushManager.ts +3 -4
- package/src/sync/submitters/types.ts +3 -4
- package/src/types.ts +9 -18
- package/src/utils/LRUCache/index.ts +2 -3
- package/src/utils/constants/browser.ts +0 -4
- package/src/utils/lang/index.ts +6 -7
- package/src/utils/lang/objectAssign.ts +13 -92
- package/src/utils/lang/sets.ts +3 -125
- package/src/utils/settingsValidation/index.ts +0 -10
- package/src/utils/settingsValidation/logger/builtinLogger.ts +1 -2
- package/src/utils/settingsValidation/storage/storageCS.ts +13 -0
- package/src/utils/settingsValidation/types.ts +0 -2
- package/types/logger/index.d.ts +1 -2
- package/types/sdkClient/clientCS.d.ts +2 -3
- package/types/sdkFactory/types.d.ts +1 -1
- package/types/storages/AbstractSplitsCacheAsync.d.ts +6 -2
- package/types/storages/AbstractSplitsCacheSync.d.ts +6 -2
- package/types/storages/KeyBuilderCS.d.ts +0 -2
- package/types/storages/dataLoader.d.ts +6 -17
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +7 -2
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +1 -2
- package/types/storages/inMemory/UniqueKeysCacheInMemory.d.ts +2 -3
- package/types/storages/inRedis/SplitsCacheInRedis.d.ts +1 -2
- package/types/storages/pluggable/SplitsCachePluggable.d.ts +1 -2
- package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -2
- package/types/storages/types.d.ts +7 -5
- package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -2
- package/types/sync/submitters/types.d.ts +3 -4
- package/types/types.d.ts +9 -17
- package/types/utils/LRUCache/index.d.ts +1 -2
- package/types/utils/constants/browser.d.ts +0 -2
- package/types/utils/lang/objectAssign.d.ts +3 -0
- package/types/utils/lang/sets.d.ts +1 -61
- package/types/utils/settingsValidation/index.d.ts +0 -1
- package/types/utils/settingsValidation/storage/storageCS.d.ts +5 -0
- package/types/utils/settingsValidation/types.d.ts +0 -2
- package/cjs/integrations/browser.js +0 -31
- package/cjs/integrations/ga/GaToSplit.js +0 -257
- package/cjs/integrations/ga/GoogleAnalyticsToSplit.js +0 -14
- package/cjs/integrations/ga/SplitToGa.js +0 -123
- package/cjs/integrations/ga/SplitToGoogleAnalytics.js +0 -14
- package/cjs/integrations/ga/types.js +0 -2
- package/cjs/sdkClient/sdkClientMethodCSWithTT.js +0 -76
- package/cjs/utils/lang/maps.js +0 -96
- package/esm/integrations/browser.js +0 -27
- package/esm/integrations/ga/GaToSplit.js +0 -250
- package/esm/integrations/ga/GoogleAnalyticsToSplit.js +0 -10
- package/esm/integrations/ga/SplitToGa.js +0 -120
- package/esm/integrations/ga/SplitToGoogleAnalytics.js +0 -10
- package/esm/integrations/ga/types.js +0 -1
- package/esm/sdkClient/sdkClientMethodCSWithTT.js +0 -72
- package/esm/utils/lang/maps.js +0 -92
- package/src/integrations/browser.ts +0 -35
- package/src/integrations/ga/GaToSplit.ts +0 -299
- package/src/integrations/ga/GoogleAnalyticsToSplit.ts +0 -14
- package/src/integrations/ga/SplitToGa.ts +0 -135
- package/src/integrations/ga/SplitToGoogleAnalytics.ts +0 -14
- package/src/integrations/ga/autoRequire.js +0 -33
- package/src/integrations/ga/types.ts +0 -153
- package/src/sdkClient/sdkClientMethodCSWithTT.ts +0 -98
- package/src/utils/lang/maps.ts +0 -108
|
@@ -4,7 +4,6 @@ import { KeyBuilder } from './KeyBuilder';
|
|
|
4
4
|
export interface MySegmentsKeyBuilder {
|
|
5
5
|
buildSegmentNameKey(segmentName: string): string;
|
|
6
6
|
extractSegmentName(builtSegmentKeyName: string): string | undefined;
|
|
7
|
-
extractOldSegmentKey(builtSegmentKeyName: string): string | undefined;
|
|
8
7
|
buildTillKey(): string;
|
|
9
8
|
}
|
|
10
9
|
|
|
@@ -33,14 +32,6 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
|
|
|
33
32
|
return builtSegmentKeyName.substr(prefix.length);
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
// @BREAKING: The key used to start with the matching key instead of the prefix, this was changed on version 10.17.3
|
|
37
|
-
extractOldSegmentKey(builtSegmentKeyName: string) {
|
|
38
|
-
const prefix = `${this.matchingKey}.${this.prefix}.segment.`;
|
|
39
|
-
|
|
40
|
-
if (startsWith(builtSegmentKeyName, prefix))
|
|
41
|
-
return builtSegmentKeyName.substr(prefix.length);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
35
|
buildLastUpdatedKey() {
|
|
45
36
|
return `${this.prefix}.splits.lastUpdated`;
|
|
46
37
|
}
|
|
@@ -66,10 +57,6 @@ export function myLargeSegmentsKeyBuilder(prefix: string, matchingKey: string):
|
|
|
66
57
|
if (startsWith(builtSegmentKeyName, p)) return builtSegmentKeyName.substr(p.length);
|
|
67
58
|
},
|
|
68
59
|
|
|
69
|
-
extractOldSegmentKey() {
|
|
70
|
-
return undefined;
|
|
71
|
-
},
|
|
72
|
-
|
|
73
60
|
buildTillKey() {
|
|
74
61
|
return `${prefix}.${matchingKey}.largeSegments.till`;
|
|
75
62
|
}
|
|
@@ -1,86 +1,55 @@
|
|
|
1
1
|
import { SplitIO } from '../types';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../utils/constants/browser';
|
|
3
|
+
import { DataLoader, ISegmentsCacheSync, ISplitsCacheSync } from './types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
|
|
6
|
+
* Factory of client-side storage loader
|
|
8
7
|
*
|
|
9
|
-
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
10
|
-
*
|
|
11
|
-
* @
|
|
12
|
-
*
|
|
13
|
-
* @TODO extend to load largeSegments
|
|
14
|
-
* @TODO extend to load data on shared mySegments storages. Be specific when emitting SDK_READY_FROM_CACHE on shared clients. Maybe the serializer should provide the `useSegments` flag.
|
|
15
|
-
* @TODO add logs, and input validation in this module, in favor of size reduction.
|
|
16
|
-
* @TODO unit tests
|
|
8
|
+
* @param preloadedData validated data following the format proposed in https://github.com/godaddy/split-javascript-data-loader
|
|
9
|
+
* and extended with a `mySegmentsData` property.
|
|
10
|
+
* @returns function to preload the storage
|
|
17
11
|
*/
|
|
18
|
-
export function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
export function dataLoaderFactory(preloadedData: SplitIO.PreloadedData): DataLoader {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Storage-agnostic adaptation of `loadDataIntoLocalStorage` function
|
|
16
|
+
* (https://github.com/godaddy/split-javascript-data-loader/blob/master/src/load-data.js)
|
|
17
|
+
*
|
|
18
|
+
* @param storage object containing `splits` and `segments` cache (client-side variant)
|
|
19
|
+
* @param userId user key string of the provided MySegmentsCache
|
|
20
|
+
*
|
|
21
|
+
* @TODO extend to support SegmentsCache (server-side variant) by making `userId` optional and adding the corresponding logic.
|
|
22
|
+
* @TODO extend to load data on shared mySegments storages. Be specific when emitting SDK_READY_FROM_CACHE on shared clients. Maybe the serializer should provide the `useSegments` flag.
|
|
23
|
+
*/
|
|
24
|
+
return function loadData(storage: { splits: ISplitsCacheSync, segments: ISegmentsCacheSync }, userId: string) {
|
|
25
|
+
// Do not load data if current preloadedData is empty
|
|
26
|
+
if (Object.keys(preloadedData).length === 0) return;
|
|
27
|
+
|
|
28
|
+
const { lastUpdated = -1, segmentsData = {}, since = -1, splitsData = {} } = preloadedData;
|
|
23
29
|
|
|
24
|
-
if (storage.splits) {
|
|
25
30
|
const storedSince = storage.splits.getChangeNumber();
|
|
31
|
+
const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
|
|
26
32
|
|
|
27
|
-
// Do not load data if current data is more recent
|
|
28
|
-
if
|
|
33
|
+
// Do not load data if current localStorage data is more recent,
|
|
34
|
+
// or if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
|
|
35
|
+
if (storedSince > since || lastUpdated < expirationTimestamp) return;
|
|
29
36
|
|
|
30
37
|
// cleaning up the localStorage data, since some cached splits might need be part of the preloaded data
|
|
31
38
|
storage.splits.clear();
|
|
32
39
|
storage.splits.setChangeNumber(since);
|
|
33
40
|
|
|
34
41
|
// splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
|
|
35
|
-
storage.splits.addSplits(splitsData.map(
|
|
36
|
-
}
|
|
42
|
+
storage.splits.addSplits(Object.keys(splitsData).map(splitName => JSON.parse(splitsData[splitName])));
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
let mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[
|
|
44
|
+
// add mySegments data
|
|
45
|
+
let mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userId];
|
|
40
46
|
if (!mySegmentsData) {
|
|
41
47
|
// segmentsData in an object where the property is the segment name and the pertaining value is a stringified object that contains the `added` array of userIds
|
|
42
48
|
mySegmentsData = Object.keys(segmentsData).filter(segmentName => {
|
|
43
|
-
const
|
|
44
|
-
return
|
|
49
|
+
const userIds = JSON.parse(segmentsData[segmentName]).added;
|
|
50
|
+
return Array.isArray(userIds) && userIds.indexOf(userId) > -1;
|
|
45
51
|
});
|
|
46
52
|
}
|
|
47
53
|
storage.segments.resetSegments({ k: mySegmentsData.map(s => ({ n: s })) });
|
|
48
|
-
} else { // add segments data (server-side)
|
|
49
|
-
Object.keys(segmentsData).filter(segmentName => {
|
|
50
|
-
const userKeys = segmentsData[segmentName];
|
|
51
|
-
storage.segments.addToSegment(segmentName, userKeys);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function getSnapshot(storage: IStorageSync, userKeys?: string[]): SplitIO.PreloadedData {
|
|
57
|
-
return {
|
|
58
|
-
// lastUpdated: Date.now(),
|
|
59
|
-
// @ts-ignore accessing private prop
|
|
60
|
-
since: storage.splits.changeNumber,
|
|
61
|
-
splitsData: storage.splits.getAll(),
|
|
62
|
-
segmentsData: userKeys ?
|
|
63
|
-
undefined : // @ts-ignore accessing private prop
|
|
64
|
-
Object.keys(storage.segments.segmentCache).reduce((prev, cur) => { // @ts-ignore accessing private prop
|
|
65
|
-
prev[cur] = setToArray(storage.segments.segmentCache[cur] as ISet<string>);
|
|
66
|
-
return prev;
|
|
67
|
-
}, {}),
|
|
68
|
-
mySegmentsData: userKeys ?
|
|
69
|
-
userKeys.reduce((prev, userKey) => {
|
|
70
|
-
// @ts-ignore accessing private prop
|
|
71
|
-
prev[userKey] = storage.shared ?
|
|
72
|
-
// Client-side segments
|
|
73
|
-
// @ts-ignore accessing private prop
|
|
74
|
-
Object.keys(storage.shared(userKey).segments.segmentCache) :
|
|
75
|
-
// Server-side segments
|
|
76
|
-
// @ts-ignore accessing private prop
|
|
77
|
-
Object.keys(storage.segments.segmentCache).reduce<string[]>((prev, segmentName) => { // @ts-ignore accessing private prop
|
|
78
|
-
return storage.segments.segmentCache[segmentName].has(userKey) ?
|
|
79
|
-
prev.concat(segmentName) :
|
|
80
|
-
prev;
|
|
81
|
-
}, []);
|
|
82
|
-
return prev;
|
|
83
|
-
}, {}) :
|
|
84
|
-
undefined
|
|
85
54
|
};
|
|
86
55
|
}
|
|
@@ -51,27 +51,7 @@ export class MySegmentsCacheInLocal extends AbstractSegmentsCacheSync {
|
|
|
51
51
|
return Object.keys(localStorage).reduce((accum, key) => {
|
|
52
52
|
let segmentName = this.keys.extractSegmentName(key);
|
|
53
53
|
|
|
54
|
-
if (segmentName)
|
|
55
|
-
accum.push(segmentName);
|
|
56
|
-
} else {
|
|
57
|
-
// @TODO @BREAKING: This is only to clean up "old" keys. Remove this whole else code block
|
|
58
|
-
segmentName = this.keys.extractOldSegmentKey(key);
|
|
59
|
-
|
|
60
|
-
if (segmentName) { // this was an old segment key, let's clean up.
|
|
61
|
-
const newSegmentKey = this.keys.buildSegmentNameKey(segmentName);
|
|
62
|
-
try {
|
|
63
|
-
// If the new format key is not there, create it.
|
|
64
|
-
if (!localStorage.getItem(newSegmentKey)) {
|
|
65
|
-
localStorage.setItem(newSegmentKey, DEFINED);
|
|
66
|
-
// we are migrating a segment, let's track it.
|
|
67
|
-
accum.push(segmentName);
|
|
68
|
-
}
|
|
69
|
-
localStorage.removeItem(key); // we migrated the current key, let's delete it.
|
|
70
|
-
} catch (e) {
|
|
71
|
-
this.log.error(e);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
54
|
+
if (segmentName) accum.push(segmentName);
|
|
75
55
|
|
|
76
56
|
return accum;
|
|
77
57
|
}, [] as string[]);
|
|
@@ -4,7 +4,6 @@ import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
|
|
|
4
4
|
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
5
5
|
import { ILogger } from '../../logger/types';
|
|
6
6
|
import { LOG_PREFIX } from './constants';
|
|
7
|
-
import { ISet, _Set, setToArray } from '../../utils/lang/sets';
|
|
8
7
|
import { ISettings } from '../../types';
|
|
9
8
|
import { getStorageHash } from '../KeyBuilder';
|
|
10
9
|
|
|
@@ -217,6 +216,15 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
217
216
|
}
|
|
218
217
|
}
|
|
219
218
|
|
|
219
|
+
/**
|
|
220
|
+
* Check if the splits information is already stored in browser LocalStorage.
|
|
221
|
+
* In this function we could add more code to check if the data is valid.
|
|
222
|
+
* @override
|
|
223
|
+
*/
|
|
224
|
+
checkCache(): boolean {
|
|
225
|
+
return this.getChangeNumber() > -1;
|
|
226
|
+
}
|
|
227
|
+
|
|
220
228
|
/**
|
|
221
229
|
* Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
|
|
222
230
|
*
|
|
@@ -241,7 +249,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
241
249
|
this.updateNewFilter = true;
|
|
242
250
|
|
|
243
251
|
// if there is cache, clear it
|
|
244
|
-
if (this.
|
|
252
|
+
if (this.checkCache()) this.clear();
|
|
245
253
|
|
|
246
254
|
} catch (e) {
|
|
247
255
|
this.log.error(LOG_PREFIX + e);
|
|
@@ -250,12 +258,12 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
250
258
|
// if the filter didn't change, nothing is done
|
|
251
259
|
}
|
|
252
260
|
|
|
253
|
-
getNamesByFlagSets(flagSets: string[]):
|
|
261
|
+
getNamesByFlagSets(flagSets: string[]): Set<string>[] {
|
|
254
262
|
return flagSets.map(flagSet => {
|
|
255
263
|
const flagSetKey = this.keys.buildFlagSetKey(flagSet);
|
|
256
264
|
const flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
257
265
|
|
|
258
|
-
return new
|
|
266
|
+
return new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
259
267
|
});
|
|
260
268
|
}
|
|
261
269
|
|
|
@@ -270,10 +278,10 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
270
278
|
|
|
271
279
|
const flagSetFromLocalStorage = localStorage.getItem(flagSetKey);
|
|
272
280
|
|
|
273
|
-
const flagSetCache = new
|
|
281
|
+
const flagSetCache = new Set(flagSetFromLocalStorage ? JSON.parse(flagSetFromLocalStorage) : []);
|
|
274
282
|
flagSetCache.add(featureFlag.name);
|
|
275
283
|
|
|
276
|
-
localStorage.setItem(flagSetKey, JSON.stringify(
|
|
284
|
+
localStorage.setItem(flagSetKey, JSON.stringify(Array.from(flagSetCache)));
|
|
277
285
|
});
|
|
278
286
|
}
|
|
279
287
|
|
|
@@ -292,7 +300,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
292
300
|
|
|
293
301
|
if (!flagSetFromLocalStorage) return;
|
|
294
302
|
|
|
295
|
-
const flagSetCache = new
|
|
303
|
+
const flagSetCache = new Set(JSON.parse(flagSetFromLocalStorage));
|
|
296
304
|
flagSetCache.delete(featureFlagName);
|
|
297
305
|
|
|
298
306
|
if (flagSetCache.size === 0) {
|
|
@@ -300,7 +308,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
300
308
|
return;
|
|
301
309
|
}
|
|
302
310
|
|
|
303
|
-
localStorage.setItem(flagSetKey, JSON.stringify(
|
|
311
|
+
localStorage.setItem(flagSetKey, JSON.stringify(Array.from(flagSetCache)));
|
|
304
312
|
}
|
|
305
313
|
|
|
306
314
|
}
|
|
@@ -12,7 +12,7 @@ import { SplitsCacheInMemory } from '../inMemory/SplitsCacheInMemory';
|
|
|
12
12
|
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../../utils/constants/browser';
|
|
13
13
|
import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS';
|
|
14
14
|
import { LOG_PREFIX } from './constants';
|
|
15
|
-
import { DEBUG,
|
|
15
|
+
import { DEBUG, NONE, STORAGE_LOCALSTORAGE } from '../../utils/constants';
|
|
16
16
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
|
|
17
17
|
import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
|
|
18
18
|
import { getMatching } from '../../utils/key';
|
|
@@ -36,7 +36,7 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
36
36
|
return InMemoryStorageCSFactory(params);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const {
|
|
39
|
+
const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation } } } = params;
|
|
40
40
|
const matchingKey = getMatching(settings.core.key);
|
|
41
41
|
const keys = new KeyBuilderCS(prefix, matchingKey);
|
|
42
42
|
const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
|
|
@@ -45,10 +45,6 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
45
45
|
const segments = new MySegmentsCacheInLocal(log, keys);
|
|
46
46
|
const largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey));
|
|
47
47
|
|
|
48
|
-
if (settings.mode === LOCALHOST_MODE || splits.getChangeNumber() > -1) {
|
|
49
|
-
Promise.resolve().then(onReadyFromCacheCb);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
48
|
return {
|
|
53
49
|
splits,
|
|
54
50
|
segments,
|
|
@@ -7,8 +7,6 @@ import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
|
|
|
7
7
|
import { DEBUG, LOCALHOST_MODE, NONE, STORAGE_MEMORY } from '../../utils/constants';
|
|
8
8
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
9
9
|
import { UniqueKeysCacheInMemoryCS } from './UniqueKeysCacheInMemoryCS';
|
|
10
|
-
import { getMatching } from '../../utils/key';
|
|
11
|
-
import { loadData } from '../dataLoader';
|
|
12
10
|
|
|
13
11
|
/**
|
|
14
12
|
* InMemory storage factory for standalone client-side SplitFactory
|
|
@@ -16,7 +14,7 @@ import { loadData } from '../dataLoader';
|
|
|
16
14
|
* @param params parameters required by EventsCacheSync
|
|
17
15
|
*/
|
|
18
16
|
export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorageSync {
|
|
19
|
-
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation }
|
|
17
|
+
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation } } } = params;
|
|
20
18
|
|
|
21
19
|
const splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
22
20
|
const segments = new MySegmentsCacheInMemory();
|
|
@@ -44,18 +42,11 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
44
42
|
},
|
|
45
43
|
|
|
46
44
|
// When using shared instanciation with MEMORY we reuse everything but segments (they are unique per key)
|
|
47
|
-
shared(
|
|
48
|
-
const segments = new MySegmentsCacheInMemory();
|
|
49
|
-
const largeSegments = new MySegmentsCacheInMemory();
|
|
50
|
-
|
|
51
|
-
if (preloadedData) {
|
|
52
|
-
loadData(preloadedData, { segments, largeSegments }, matchingKey);
|
|
53
|
-
}
|
|
54
|
-
|
|
45
|
+
shared() {
|
|
55
46
|
return {
|
|
56
47
|
splits: this.splits,
|
|
57
|
-
segments,
|
|
58
|
-
largeSegments,
|
|
48
|
+
segments: new MySegmentsCacheInMemory(),
|
|
49
|
+
largeSegments: new MySegmentsCacheInMemory(),
|
|
59
50
|
impressions: this.impressions,
|
|
60
51
|
impressionCounts: this.impressionCounts,
|
|
61
52
|
events: this.events,
|
|
@@ -81,12 +72,6 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
81
72
|
if (storage.uniqueKeys) storage.uniqueKeys.track = noopTrack;
|
|
82
73
|
}
|
|
83
74
|
|
|
84
|
-
|
|
85
|
-
if (preloadedData) {
|
|
86
|
-
loadData(preloadedData, storage, getMatching(params.settings.core.key));
|
|
87
|
-
if (splits.getChangeNumber() > -1) onReadyFromCacheCb();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
75
|
return storage;
|
|
91
76
|
}
|
|
92
77
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AbstractSegmentsCacheSync } from '../AbstractSegmentsCacheSync';
|
|
2
|
-
import { ISet, _Set } from '../../utils/lang/sets';
|
|
3
2
|
import { isIntegerNumber } from '../../utils/lang';
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -8,12 +7,12 @@ import { isIntegerNumber } from '../../utils/lang';
|
|
|
8
7
|
*/
|
|
9
8
|
export class SegmentsCacheInMemory extends AbstractSegmentsCacheSync {
|
|
10
9
|
|
|
11
|
-
private segmentCache: Record<string,
|
|
10
|
+
private segmentCache: Record<string, Set<string>> = {};
|
|
12
11
|
private segmentChangeNumber: Record<string, number> = {};
|
|
13
12
|
|
|
14
13
|
addToSegment(name: string, segmentKeys: string[]): boolean {
|
|
15
14
|
const values = this.segmentCache[name];
|
|
16
|
-
const keySet = values ? values : new
|
|
15
|
+
const keySet = values ? values : new Set<string>();
|
|
17
16
|
|
|
18
17
|
segmentKeys.forEach(k => keySet.add(k));
|
|
19
18
|
|
|
@@ -24,7 +23,7 @@ export class SegmentsCacheInMemory extends AbstractSegmentsCacheSync {
|
|
|
24
23
|
|
|
25
24
|
removeFromSegment(name: string, segmentKeys: string[]): boolean {
|
|
26
25
|
const values = this.segmentCache[name];
|
|
27
|
-
const keySet = values ? values : new
|
|
26
|
+
const keySet = values ? values : new Set<string>();
|
|
28
27
|
|
|
29
28
|
segmentKeys.forEach(k => keySet.delete(k));
|
|
30
29
|
|
|
@@ -50,7 +49,7 @@ export class SegmentsCacheInMemory extends AbstractSegmentsCacheSync {
|
|
|
50
49
|
|
|
51
50
|
private _registerSegment(name: string) {
|
|
52
51
|
if (!this.segmentCache[name]) {
|
|
53
|
-
this.segmentCache[name] = new
|
|
52
|
+
this.segmentCache[name] = new Set<string>();
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
return true;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ISplit, ISplitFiltersValidation } from '../../dtos/types';
|
|
2
2
|
import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
|
|
3
3
|
import { isFiniteNumber } from '../../utils/lang';
|
|
4
|
-
import { ISet, _Set } from '../../utils/lang/sets';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Default ISplitsCacheSync implementation that stores split definitions in memory.
|
|
@@ -14,7 +13,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
14
13
|
private ttCache: Record<string, number> = {};
|
|
15
14
|
private changeNumber: number = -1;
|
|
16
15
|
private segmentsCount: number = 0;
|
|
17
|
-
private flagSetsCache: Record<string,
|
|
16
|
+
private flagSetsCache: Record<string, Set<string>> = {};
|
|
18
17
|
|
|
19
18
|
constructor(splitFiltersValidation?: ISplitFiltersValidation) {
|
|
20
19
|
super();
|
|
@@ -104,8 +103,8 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
104
103
|
return this.getChangeNumber() === -1 || this.segmentsCount > 0;
|
|
105
104
|
}
|
|
106
105
|
|
|
107
|
-
getNamesByFlagSets(flagSets: string[]):
|
|
108
|
-
return flagSets.map(flagSet => this.flagSetsCache[flagSet] || new
|
|
106
|
+
getNamesByFlagSets(flagSets: string[]): Set<string>[] {
|
|
107
|
+
return flagSets.map(flagSet => this.flagSetsCache[flagSet] || new Set());
|
|
109
108
|
}
|
|
110
109
|
|
|
111
110
|
private addToFlagSets(featureFlag: ISplit) {
|
|
@@ -114,7 +113,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
114
113
|
|
|
115
114
|
if (this.flagSetsFilter.length > 0 && !this.flagSetsFilter.some(filterFlagSet => filterFlagSet === featureFlagSet)) return;
|
|
116
115
|
|
|
117
|
-
if (!this.flagSetsCache[featureFlagSet]) this.flagSetsCache[featureFlagSet] = new
|
|
116
|
+
if (!this.flagSetsCache[featureFlagSet]) this.flagSetsCache[featureFlagSet] = new Set([]);
|
|
118
117
|
|
|
119
118
|
this.flagSetsCache[featureFlagSet].add(featureFlag.name);
|
|
120
119
|
});
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { IUniqueKeysCacheBase } from '../types';
|
|
2
|
-
import { ISet, setToArray, _Set } from '../../utils/lang/sets';
|
|
3
2
|
import { UniqueKeysPayloadSs } from '../../sync/submitters/types';
|
|
4
3
|
import { DEFAULT_CACHE_SIZE } from '../inRedis/constants';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Converts `uniqueKeys` data from cache into request payload for SS.
|
|
8
7
|
*/
|
|
9
|
-
export function fromUniqueKeysCollector(uniqueKeys: { [featureName: string]:
|
|
8
|
+
export function fromUniqueKeysCollector(uniqueKeys: { [featureName: string]: Set<string> }): UniqueKeysPayloadSs {
|
|
10
9
|
const payload = [];
|
|
11
10
|
const featureNames = Object.keys(uniqueKeys);
|
|
12
11
|
for (let i = 0; i < featureNames.length; i++) {
|
|
13
12
|
const featureName = featureNames[i];
|
|
14
|
-
const userKeys =
|
|
13
|
+
const userKeys = Array.from(uniqueKeys[featureName]);
|
|
15
14
|
const uniqueKeysPayload = {
|
|
16
15
|
f: featureName,
|
|
17
16
|
ks: userKeys
|
|
@@ -27,7 +26,7 @@ export class UniqueKeysCacheInMemory implements IUniqueKeysCacheBase {
|
|
|
27
26
|
protected onFullQueue?: () => void;
|
|
28
27
|
private readonly maxStorage: number;
|
|
29
28
|
private uniqueTrackerSize = 0;
|
|
30
|
-
protected uniqueKeysTracker: { [featureName: string]:
|
|
29
|
+
protected uniqueKeysTracker: { [featureName: string]: Set<string> } = {};
|
|
31
30
|
|
|
32
31
|
constructor(uniqueKeysQueueSize = DEFAULT_CACHE_SIZE) {
|
|
33
32
|
this.maxStorage = uniqueKeysQueueSize;
|
|
@@ -41,7 +40,7 @@ export class UniqueKeysCacheInMemory implements IUniqueKeysCacheBase {
|
|
|
41
40
|
* Store unique keys per feature.
|
|
42
41
|
*/
|
|
43
42
|
track(userKey: string, featureName: string) {
|
|
44
|
-
if (!this.uniqueKeysTracker[featureName]) this.uniqueKeysTracker[featureName] = new
|
|
43
|
+
if (!this.uniqueKeysTracker[featureName]) this.uniqueKeysTracker[featureName] = new Set();
|
|
45
44
|
const tracker = this.uniqueKeysTracker[featureName];
|
|
46
45
|
if (!tracker.has(userKey)) {
|
|
47
46
|
tracker.add(userKey);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { IUniqueKeysCacheBase } from '../types';
|
|
2
|
-
import { ISet, setToArray, _Set } from '../../utils/lang/sets';
|
|
3
2
|
import { UniqueKeysPayloadCs } from '../../sync/submitters/types';
|
|
4
3
|
import { DEFAULT_CACHE_SIZE } from '../inRedis/constants';
|
|
5
4
|
|
|
@@ -8,7 +7,7 @@ export class UniqueKeysCacheInMemoryCS implements IUniqueKeysCacheBase {
|
|
|
8
7
|
private onFullQueue?: () => void;
|
|
9
8
|
private readonly maxStorage: number;
|
|
10
9
|
private uniqueTrackerSize = 0;
|
|
11
|
-
private uniqueKeysTracker: { [userKey: string]:
|
|
10
|
+
private uniqueKeysTracker: { [userKey: string]: Set<string> } = {};
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
*
|
|
@@ -28,7 +27,7 @@ export class UniqueKeysCacheInMemoryCS implements IUniqueKeysCacheBase {
|
|
|
28
27
|
*/
|
|
29
28
|
track(userKey: string, featureName: string) {
|
|
30
29
|
|
|
31
|
-
if (!this.uniqueKeysTracker[userKey]) this.uniqueKeysTracker[userKey] = new
|
|
30
|
+
if (!this.uniqueKeysTracker[userKey]) this.uniqueKeysTracker[userKey] = new Set();
|
|
32
31
|
const tracker = this.uniqueKeysTracker[userKey];
|
|
33
32
|
if (!tracker.has(featureName)) {
|
|
34
33
|
tracker.add(featureName);
|
|
@@ -66,12 +65,12 @@ export class UniqueKeysCacheInMemoryCS implements IUniqueKeysCacheBase {
|
|
|
66
65
|
/**
|
|
67
66
|
* Converts `uniqueKeys` data from cache into request payload.
|
|
68
67
|
*/
|
|
69
|
-
private fromUniqueKeysCollector(uniqueKeys: { [userKey: string]:
|
|
68
|
+
private fromUniqueKeysCollector(uniqueKeys: { [userKey: string]: Set<string> }): UniqueKeysPayloadCs {
|
|
70
69
|
const payload = [];
|
|
71
70
|
const userKeys = Object.keys(uniqueKeys);
|
|
72
71
|
for (let k = 0; k < userKeys.length; k++) {
|
|
73
72
|
const userKey = userKeys[k];
|
|
74
|
-
const featureNames =
|
|
73
|
+
const featureNames = Array.from(uniqueKeys[userKey]);
|
|
75
74
|
const uniqueKeysPayload = {
|
|
76
75
|
k: userKey,
|
|
77
76
|
fs: featureNames
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import ioredis, { Pipeline } from 'ioredis';
|
|
2
2
|
import { ILogger } from '../../logger/types';
|
|
3
3
|
import { merge, isString } from '../../utils/lang';
|
|
4
|
-
import { _Set, setToArray, ISet } from '../../utils/lang/sets';
|
|
5
4
|
import { thenable } from '../../utils/promise/thenable';
|
|
6
5
|
import { timeout } from '../../utils/promise/timeout';
|
|
7
6
|
|
|
@@ -37,7 +36,7 @@ export class RedisAdapter extends ioredis {
|
|
|
37
36
|
private readonly log: ILogger;
|
|
38
37
|
private _options: object;
|
|
39
38
|
private _notReadyCommandsQueue?: IRedisCommand[];
|
|
40
|
-
private _runningCommands:
|
|
39
|
+
private _runningCommands: Set<Promise<any>>;
|
|
41
40
|
|
|
42
41
|
constructor(log: ILogger, storageSettings: Record<string, any> = {}) {
|
|
43
42
|
const options = RedisAdapter._defineOptions(storageSettings);
|
|
@@ -47,7 +46,7 @@ export class RedisAdapter extends ioredis {
|
|
|
47
46
|
this.log = log;
|
|
48
47
|
this._options = options;
|
|
49
48
|
this._notReadyCommandsQueue = [];
|
|
50
|
-
this._runningCommands = new
|
|
49
|
+
this._runningCommands = new Set();
|
|
51
50
|
this._listenToEvents();
|
|
52
51
|
this._setTimeoutWrappers();
|
|
53
52
|
this._setDisconnectWrapper();
|
|
@@ -150,7 +149,7 @@ export class RedisAdapter extends ioredis {
|
|
|
150
149
|
if (instance._runningCommands.size > 0) {
|
|
151
150
|
instance.log.info(LOG_PREFIX + `Attempting to disconnect but there are ${instance._runningCommands.size} commands still waiting for resolution. Defering disconnection until those finish.`);
|
|
152
151
|
|
|
153
|
-
Promise.all(
|
|
152
|
+
Promise.all(Array.from(instance._runningCommands))
|
|
154
153
|
.then(() => {
|
|
155
154
|
instance.log.debug(LOG_PREFIX + 'Pending commands finished successfully, disconnecting.');
|
|
156
155
|
originalMethod.apply(instance, params);
|
|
@@ -4,7 +4,7 @@ import { ILogger } from '../../logger/types';
|
|
|
4
4
|
import { LOG_PREFIX } from './constants';
|
|
5
5
|
import { ISplit, ISplitFiltersValidation } from '../../dtos/types';
|
|
6
6
|
import { AbstractSplitsCacheAsync } from '../AbstractSplitsCacheAsync';
|
|
7
|
-
import {
|
|
7
|
+
import { returnDifference } from '../../utils/lang/sets';
|
|
8
8
|
import type { RedisAdapter } from './RedisAdapter';
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -215,14 +215,14 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
215
215
|
* The returned promise is resolved with the list of feature flag names per flag set,
|
|
216
216
|
* or rejected if the pipelined redis operation fails (e.g., timeout).
|
|
217
217
|
*/
|
|
218
|
-
getNamesByFlagSets(flagSets: string[]): Promise<
|
|
218
|
+
getNamesByFlagSets(flagSets: string[]): Promise<Set<string>[]> {
|
|
219
219
|
return this.redis.pipeline(flagSets.map(flagSet => ['smembers', this.keys.buildFlagSetKey(flagSet)])).exec()
|
|
220
220
|
.then((results) => results.map(([e, value], index) => {
|
|
221
221
|
if (e === null) return value;
|
|
222
222
|
|
|
223
223
|
this.log.error(LOG_PREFIX + `Could not read result from get members of flag set ${flagSets[index]} due to an error: ${e}`);
|
|
224
224
|
}))
|
|
225
|
-
.then(namesByFlagSets => namesByFlagSets.map(namesByFlagSet => new
|
|
225
|
+
.then(namesByFlagSets => namesByFlagSets.map(namesByFlagSet => new Set(namesByFlagSet)));
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
/**
|
|
@@ -6,7 +6,6 @@ import { findLatencyIndex } from '../findLatencyIndex';
|
|
|
6
6
|
import { getTelemetryConfigStats } from '../../sync/submitters/telemetrySubmitter';
|
|
7
7
|
import { CONSUMER_MODE, STORAGE_REDIS } from '../../utils/constants';
|
|
8
8
|
import { isNaNNumber, isString } from '../../utils/lang';
|
|
9
|
-
import { _Map } from '../../utils/lang/maps';
|
|
10
9
|
import { MAX_LATENCY_BUCKET_COUNT, newBuckets } from '../inMemory/TelemetryCacheInMemory';
|
|
11
10
|
import { parseLatencyField, parseExceptionField, parseMetadata } from '../utils';
|
|
12
11
|
import type { RedisAdapter } from './RedisAdapter';
|
|
@@ -46,7 +45,7 @@ export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
|
46
45
|
popLatencies(): Promise<MultiMethodLatencies> {
|
|
47
46
|
return this.redis.hgetall(this.keys.latencyPrefix).then(latencies => {
|
|
48
47
|
|
|
49
|
-
const result: MultiMethodLatencies = new
|
|
48
|
+
const result: MultiMethodLatencies = new Map();
|
|
50
49
|
|
|
51
50
|
Object.keys(latencies).forEach(field => {
|
|
52
51
|
|
|
@@ -86,7 +85,7 @@ export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
|
86
85
|
popExceptions(): Promise<MultiMethodExceptions> {
|
|
87
86
|
return this.redis.hgetall(this.keys.exceptionPrefix).then(exceptions => {
|
|
88
87
|
|
|
89
|
-
const result: MultiMethodExceptions = new
|
|
88
|
+
const result: MultiMethodExceptions = new Map();
|
|
90
89
|
|
|
91
90
|
Object.keys(exceptions).forEach(field => {
|
|
92
91
|
|
|
@@ -119,7 +118,7 @@ export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
|
119
118
|
popConfigs(): Promise<MultiConfigs> {
|
|
120
119
|
return this.redis.hgetall(this.keys.initPrefix).then(configs => {
|
|
121
120
|
|
|
122
|
-
const result: MultiConfigs = new
|
|
121
|
+
const result: MultiConfigs = new Map();
|
|
123
122
|
|
|
124
123
|
Object.keys(configs).forEach(field => {
|
|
125
124
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { IUniqueKeysCacheBase } from '../types';
|
|
2
2
|
import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
|
|
3
|
-
import { setToArray } from '../../utils/lang/sets';
|
|
4
3
|
import { DEFAULT_CACHE_SIZE, REFRESH_RATE, TTL_REFRESH } from './constants';
|
|
5
4
|
import { LOG_PREFIX } from './constants';
|
|
6
5
|
import { ILogger } from '../../logger/types';
|
|
@@ -29,7 +28,7 @@ export class UniqueKeysCacheInRedis extends UniqueKeysCacheInMemory implements I
|
|
|
29
28
|
if (!featureNames.length) return Promise.resolve(false);
|
|
30
29
|
|
|
31
30
|
const uniqueKeysArray = featureNames.map((featureName) => {
|
|
32
|
-
const featureKeys =
|
|
31
|
+
const featureKeys = Array.from(this.uniqueKeysTracker[featureName]);
|
|
33
32
|
const uniqueKeysPayload = {
|
|
34
33
|
f: featureName,
|
|
35
34
|
ks: featureKeys
|
|
@@ -5,7 +5,6 @@ import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
|
5
5
|
import { IPluggableStorageWrapper, ISegmentsCacheAsync } from '../types';
|
|
6
6
|
import { ILogger } from '../../logger/types';
|
|
7
7
|
import { LOG_PREFIX } from './constants';
|
|
8
|
-
import { _Set } from '../../utils/lang/sets';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* ISegmentsCacheAsync implementation for pluggable storages.
|
|
@@ -5,7 +5,7 @@ import { ILogger } from '../../logger/types';
|
|
|
5
5
|
import { ISplit, ISplitFiltersValidation } from '../../dtos/types';
|
|
6
6
|
import { LOG_PREFIX } from './constants';
|
|
7
7
|
import { AbstractSplitsCacheAsync } from '../AbstractSplitsCacheAsync';
|
|
8
|
-
import {
|
|
8
|
+
import { returnDifference } from '../../utils/lang/sets';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* ISplitsCacheAsync implementation for pluggable storages.
|
|
@@ -181,11 +181,11 @@ export class SplitsCachePluggable extends AbstractSplitsCacheAsync {
|
|
|
181
181
|
* The returned promise is resolved with the list of feature flag names per flag set.
|
|
182
182
|
* It never rejects (If there is a wrapper error for some flag set, an empty set is returned for it).
|
|
183
183
|
*/
|
|
184
|
-
getNamesByFlagSets(flagSets: string[]): Promise<
|
|
184
|
+
getNamesByFlagSets(flagSets: string[]): Promise<Set<string>[]> {
|
|
185
185
|
return Promise.all(flagSets.map(flagSet => {
|
|
186
186
|
const flagSetKey = this.keys.buildFlagSetKey(flagSet);
|
|
187
187
|
return this.wrapper.getItems(flagSetKey).catch(() => []);
|
|
188
|
-
})).then(namesByFlagSets => namesByFlagSets.map(namesByFlagSet => new
|
|
188
|
+
})).then(namesByFlagSets => namesByFlagSets.map(namesByFlagSet => new Set(namesByFlagSet)));
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
/**
|