@splitsoftware/splitio-commons 1.6.2-rc.0 → 1.6.2-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +4 -0
- package/cjs/consent/sdkUserConsent.js +2 -2
- package/cjs/evaluator/index.js +15 -16
- package/cjs/integrations/ga/GaToSplit.js +8 -5
- package/cjs/listeners/browser.js +2 -1
- package/cjs/logger/constants.js +2 -1
- package/cjs/sdkClient/client.js +19 -7
- package/cjs/sdkClient/sdkClient.js +3 -1
- package/cjs/sdkFactory/index.js +24 -7
- package/cjs/sdkManager/index.js +3 -11
- package/cjs/services/splitApi.js +24 -4
- package/cjs/storages/AbstractSplitsCacheAsync.js +8 -10
- package/cjs/storages/AbstractSplitsCacheSync.js +8 -10
- package/cjs/storages/KeyBuilderSS.js +54 -9
- package/cjs/storages/dataLoader.js +1 -1
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +5 -7
- package/cjs/storages/inLocalStorage/index.js +5 -1
- package/cjs/storages/inMemory/ImpressionCountsCacheInMemory.js +12 -1
- package/cjs/storages/inMemory/InMemoryStorage.js +6 -2
- package/cjs/storages/inMemory/InMemoryStorageCS.js +6 -2
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +7 -10
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +10 -5
- package/cjs/storages/inMemory/UniqueKeysCacheInMemory.js +73 -0
- package/cjs/storages/inMemory/UniqueKeysCacheInMemoryCS.js +78 -0
- package/cjs/storages/inRedis/EventsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/ImpressionCountsCacheInRedis.js +50 -0
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +15 -9
- package/cjs/storages/inRedis/TelemetryCacheInRedis.js +100 -0
- package/cjs/storages/inRedis/UniqueKeysCacheInRedis.js +59 -0
- package/cjs/storages/inRedis/constants.js +4 -1
- package/cjs/storages/inRedis/index.js +17 -2
- package/cjs/storages/pluggable/ImpressionCountsCachePluggable.js +43 -0
- package/cjs/storages/pluggable/SplitsCachePluggable.js +14 -9
- package/cjs/storages/pluggable/TelemetryCachePluggable.js +126 -0
- package/cjs/storages/pluggable/UniqueKeysCachePluggable.js +50 -0
- package/cjs/storages/pluggable/index.js +42 -17
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -1
- package/cjs/sync/submitters/submitterManager.js +3 -0
- package/cjs/sync/submitters/telemetrySubmitter.js +8 -4
- package/cjs/sync/submitters/uniqueKeysSubmitter.js +27 -0
- package/cjs/trackers/impressionsTracker.js +22 -41
- package/cjs/trackers/strategy/strategyDebug.js +25 -0
- package/cjs/trackers/strategy/strategyNone.js +29 -0
- package/cjs/trackers/strategy/strategyOptimized.js +35 -0
- package/cjs/trackers/telemetryTracker.js +6 -0
- package/cjs/trackers/uniqueKeysTracker.js +38 -0
- package/cjs/utils/constants/index.js +4 -2
- package/cjs/utils/lang/maps.js +15 -7
- package/cjs/utils/redis/RedisMock.js +31 -0
- package/cjs/utils/settingsValidation/impressionsMode.js +2 -2
- package/esm/consent/sdkUserConsent.js +2 -2
- package/esm/evaluator/index.js +15 -16
- package/esm/integrations/ga/GaToSplit.js +8 -5
- package/esm/listeners/browser.js +3 -2
- package/esm/logger/constants.js +1 -0
- package/esm/sdkClient/client.js +19 -7
- package/esm/sdkClient/sdkClient.js +3 -1
- package/esm/sdkFactory/index.js +24 -7
- package/esm/sdkManager/index.js +3 -11
- package/esm/services/splitApi.js +24 -4
- package/esm/storages/AbstractSplitsCacheAsync.js +8 -10
- package/esm/storages/AbstractSplitsCacheSync.js +8 -10
- package/esm/storages/KeyBuilderSS.js +50 -8
- package/esm/storages/dataLoader.js +1 -1
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +5 -7
- package/esm/storages/inLocalStorage/index.js +6 -2
- package/esm/storages/inMemory/ImpressionCountsCacheInMemory.js +12 -1
- package/esm/storages/inMemory/InMemoryStorage.js +8 -4
- package/esm/storages/inMemory/InMemoryStorageCS.js +7 -3
- package/esm/storages/inMemory/SplitsCacheInMemory.js +7 -10
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +9 -5
- package/esm/storages/inMemory/UniqueKeysCacheInMemory.js +70 -0
- package/esm/storages/inMemory/UniqueKeysCacheInMemoryCS.js +75 -0
- package/esm/storages/inRedis/EventsCacheInRedis.js +1 -1
- package/esm/storages/inRedis/ImpressionCountsCacheInRedis.js +47 -0
- package/esm/storages/inRedis/SplitsCacheInRedis.js +15 -9
- package/esm/storages/inRedis/TelemetryCacheInRedis.js +100 -0
- package/esm/storages/inRedis/UniqueKeysCacheInRedis.js +56 -0
- package/esm/storages/inRedis/constants.js +3 -0
- package/esm/storages/inRedis/index.js +18 -3
- package/esm/storages/pluggable/ImpressionCountsCachePluggable.js +40 -0
- package/esm/storages/pluggable/SplitsCachePluggable.js +14 -9
- package/esm/storages/pluggable/TelemetryCachePluggable.js +126 -0
- package/esm/storages/pluggable/UniqueKeysCachePluggable.js +47 -0
- package/esm/storages/pluggable/index.js +43 -18
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +2 -3
- package/esm/sync/polling/updaters/splitChangesUpdater.js +1 -1
- package/esm/sync/submitters/submitterManager.js +3 -0
- package/esm/sync/submitters/telemetrySubmitter.js +9 -5
- package/esm/sync/submitters/uniqueKeysSubmitter.js +23 -0
- package/esm/trackers/impressionsTracker.js +22 -41
- package/esm/trackers/strategy/strategyDebug.js +21 -0
- package/esm/trackers/strategy/strategyNone.js +25 -0
- package/esm/trackers/strategy/strategyOptimized.js +31 -0
- package/esm/trackers/telemetryTracker.js +6 -0
- package/esm/trackers/uniqueKeysTracker.js +34 -0
- package/esm/utils/constants/index.js +2 -0
- package/esm/utils/lang/maps.js +15 -7
- package/esm/utils/redis/RedisMock.js +28 -0
- package/esm/utils/settingsValidation/impressionsMode.js +3 -3
- package/package.json +1 -2
- package/src/consent/sdkUserConsent.ts +2 -2
- package/src/evaluator/index.ts +14 -15
- package/src/integrations/ga/GaToSplit.ts +9 -5
- package/src/integrations/types.ts +2 -1
- package/src/listeners/browser.ts +3 -2
- package/src/logger/constants.ts +1 -0
- package/src/sdkClient/client.ts +21 -8
- package/src/sdkClient/sdkClient.ts +3 -1
- package/src/sdkFactory/index.ts +28 -8
- package/src/sdkFactory/types.ts +7 -4
- package/src/sdkManager/index.ts +3 -12
- package/src/services/splitApi.ts +26 -4
- package/src/services/types.ts +8 -2
- package/src/storages/AbstractSplitsCacheAsync.ts +13 -15
- package/src/storages/AbstractSplitsCacheSync.ts +15 -17
- package/src/storages/KeyBuilderSS.ts +61 -9
- package/src/storages/dataLoader.ts +1 -1
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +8 -11
- package/src/storages/inLocalStorage/index.ts +5 -2
- package/src/storages/inMemory/ImpressionCountsCacheInMemory.ts +16 -1
- package/src/storages/inMemory/InMemoryStorage.ts +7 -4
- package/src/storages/inMemory/InMemoryStorageCS.ts +6 -3
- package/src/storages/inMemory/SplitsCacheInMemory.ts +10 -14
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +10 -6
- package/src/storages/inMemory/UniqueKeysCacheInMemory.ts +82 -0
- package/src/storages/inMemory/UniqueKeysCacheInMemoryCS.ts +88 -0
- package/src/storages/inRedis/EventsCacheInRedis.ts +1 -1
- package/src/storages/inRedis/ImpressionCountsCacheInRedis.ts +53 -0
- package/src/storages/inRedis/SplitsCacheInRedis.ts +21 -17
- package/src/storages/inRedis/TelemetryCacheInRedis.ts +122 -2
- package/src/storages/inRedis/UniqueKeysCacheInRedis.ts +65 -0
- package/src/storages/inRedis/constants.ts +3 -0
- package/src/storages/inRedis/index.ts +15 -5
- package/src/storages/pluggable/ImpressionCountsCachePluggable.ts +47 -0
- package/src/storages/pluggable/SplitsCachePluggable.ts +20 -17
- package/src/storages/pluggable/TelemetryCachePluggable.ts +147 -2
- package/src/storages/pluggable/UniqueKeysCachePluggable.ts +56 -0
- package/src/storages/pluggable/index.ts +44 -19
- package/src/storages/types.ts +50 -29
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +5 -6
- package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -2
- package/src/sync/submitters/submitterManager.ts +2 -0
- package/src/sync/submitters/telemetrySubmitter.ts +15 -8
- package/src/sync/submitters/types.ts +38 -7
- package/src/sync/submitters/uniqueKeysSubmitter.ts +36 -0
- package/src/trackers/impressionsTracker.ts +27 -48
- package/src/trackers/strategy/strategyDebug.ts +28 -0
- package/src/trackers/strategy/strategyNone.ts +34 -0
- package/src/trackers/strategy/strategyOptimized.ts +42 -0
- package/src/trackers/telemetryTracker.ts +7 -2
- package/src/trackers/types.ts +32 -0
- package/src/trackers/uniqueKeysTracker.ts +48 -0
- package/src/types.ts +1 -1
- package/src/utils/constants/index.ts +2 -0
- package/src/utils/lang/maps.ts +20 -8
- package/src/utils/redis/RedisMock.ts +33 -0
- package/src/utils/settingsValidation/impressionsMode.ts +3 -3
- package/src/utils/settingsValidation/index.ts +1 -0
- package/types/integrations/types.d.ts +2 -1
- package/types/logger/browser/{debugLogger.d.ts → DebugLogger.d.ts} +0 -0
- package/types/logger/browser/{errorLogger.d.ts → ErrorLogger.d.ts} +0 -0
- package/types/logger/browser/{infoLogger.d.ts → InfoLogger.d.ts} +0 -0
- package/types/logger/browser/{warnLogger.d.ts → WarnLogger.d.ts} +0 -0
- package/types/logger/constants.d.ts +1 -0
- package/types/sdkFactory/types.d.ts +4 -2
- package/types/services/types.d.ts +6 -2
- package/types/storages/AbstractSplitsCacheAsync.d.ts +7 -6
- package/types/storages/AbstractSplitsCacheSync.d.ts +6 -6
- package/types/storages/KeyBuilderSS.d.ts +9 -2
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +3 -4
- package/types/storages/inMemory/ImpressionCountsCacheInMemory.d.ts +5 -1
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +3 -2
- package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -3
- package/types/storages/inMemory/uniqueKeysCacheInMemory.d.ts +35 -0
- package/types/storages/inMemory/uniqueKeysCacheInMemoryCS.d.ts +37 -0
- package/types/storages/inRedis/EventsCacheInRedis.d.ts +1 -1
- package/types/storages/inRedis/ImpressionCountsCacheInRedis.d.ts +14 -0
- package/types/storages/inRedis/SplitsCacheInRedis.d.ts +6 -5
- package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +16 -1
- package/types/storages/inRedis/constants.d.ts +3 -0
- package/types/storages/inRedis/uniqueKeysCacheInRedis.d.ts +15 -0
- package/types/storages/pluggable/ImpressionCountsCachePluggable.d.ts +14 -0
- package/types/storages/pluggable/SplitsCachePluggable.d.ts +6 -5
- package/types/storages/pluggable/TelemetryCachePluggable.d.ts +17 -1
- package/types/storages/pluggable/UniqueKeysCachePluggable.d.ts +14 -0
- package/types/storages/types.d.ts +38 -25
- package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -1
- package/types/sync/submitters/telemetrySubmitter.d.ts +1 -1
- package/types/sync/submitters/types.d.ts +30 -7
- package/types/sync/submitters/uniqueKeysSubmitter.d.ts +0 -8
- package/types/trackers/impressionsTracker.d.ts +4 -6
- package/types/trackers/types.d.ts +27 -0
- package/types/trackers/uniqueKeysTracker.d.ts +3 -3
- package/types/types.d.ts +1 -1
- package/types/utils/constants/index.d.ts +2 -0
- package/types/utils/lang/maps.d.ts +6 -2
- package/types/utils/redis/RedisMock.d.ts +4 -0
- package/src/splitio.d.ts +0 -1602
- package/types/integrations/ga/GaToSplitPlugin.d.ts +0 -3
- package/types/integrations/ga/SplitToGaPlugin.d.ts +0 -4
- package/types/integrations/ga/autoRequire.d.ts +0 -4
- package/types/logger/codes.d.ts +0 -2
- package/types/logger/codesConstants.d.ts +0 -117
- package/types/logger/codesConstantsBrowser.d.ts +0 -2
- package/types/logger/codesConstantsNode.d.ts +0 -14
- package/types/logger/codesDebug.d.ts +0 -1
- package/types/logger/codesDebugBrowser.d.ts +0 -1
- package/types/logger/codesDebugNode.d.ts +0 -1
- package/types/logger/codesError.d.ts +0 -1
- package/types/logger/codesErrorNode.d.ts +0 -1
- package/types/logger/codesInfo.d.ts +0 -1
- package/types/logger/codesWarn.d.ts +0 -1
- package/types/logger/codesWarnNode.d.ts +0 -1
- package/types/logger/debugLogger.d.ts +0 -2
- package/types/logger/errorLogger.d.ts +0 -2
- package/types/logger/infoLogger.d.ts +0 -2
- package/types/logger/messages/debugBrowser.d.ts +0 -1
- package/types/logger/messages/debugNode.d.ts +0 -1
- package/types/logger/messages/errorNode.d.ts +0 -1
- package/types/logger/messages/warnNode.d.ts +0 -1
- package/types/logger/noopLogger.d.ts +0 -2
- package/types/logger/warnLogger.d.ts +0 -2
- package/types/sdkClient/types.d.ts +0 -18
- package/types/sdkFactory/userConsentProps.d.ts +0 -6
- package/types/sdkManager/sdkManagerMethod.d.ts +0 -6
- package/types/storages/getRegisteredSegments.d.ts +0 -10
- package/types/storages/inMemory/CountsCacheInMemory.d.ts +0 -20
- package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +0 -20
- package/types/storages/inMemory/index.d.ts +0 -10
- package/types/storages/inRedis/CountsCacheInRedis.d.ts +0 -9
- package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +0 -9
- package/types/storages/parseSegments.d.ts +0 -6
- package/types/sync/offline/LocalhostFromFile.d.ts +0 -2
- package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +0 -2
- package/types/sync/polling/syncTasks/splitsSyncTask.copy.d.ts +0 -35
- package/types/sync/polling/syncTasks/splitsSyncTask.morelikeoriginal.d.ts +0 -35
- package/types/sync/streaming/AuthClient/indexV1.d.ts +0 -12
- package/types/sync/streaming/AuthClient/indexV2.d.ts +0 -8
- package/types/sync/streaming/pushManagerCS.d.ts +0 -1
- package/types/sync/streaming/pushManagerNoUsers.d.ts +0 -13
- package/types/sync/streaming/pushManagerSS.d.ts +0 -1
- package/types/sync/submitters/eventsSyncTask.d.ts +0 -8
- package/types/sync/submitters/impressionCountsSyncTask.d.ts +0 -13
- package/types/sync/submitters/impressionsSyncTask.d.ts +0 -14
- package/types/sync/submitters/metricsSyncTask.d.ts +0 -12
- package/types/sync/submitters/submitterSyncTask.d.ts +0 -10
- package/types/sync/submitters/telemetrySyncTask.d.ts +0 -0
- package/types/sync/syncManagerFromFile.d.ts +0 -2
- package/types/sync/syncManagerFromObject.d.ts +0 -2
- package/types/sync/syncManagerOffline.d.ts +0 -9
- package/types/sync/syncTaskComposite.d.ts +0 -5
- package/types/trackers/telemetryRecorder.d.ts +0 -0
- package/types/utils/EventEmitter.d.ts +0 -4
- package/types/utils/consent.d.ts +0 -2
- package/types/utils/lang/errors.d.ts +0 -10
- package/types/utils/murmur3/commons.d.ts +0 -12
- package/types/utils/settingsValidation/buildMetadata.d.ts +0 -3
- package/types/utils/settingsValidation/localhost/index.d.ts +0 -9
- package/types/utils/settingsValidation/logger.d.ts +0 -11
- package/types/utils/settingsValidation/runtime/browser.d.ts +0 -2
- package/types/utils/settingsValidation/runtime/node.d.ts +0 -2
- package/types/utils/settingsValidation/userConsent.d.ts +0 -5
- package/types/utils/timeTracker/index.d.ts +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ISplitsCacheAsync } from './types';
|
|
2
2
|
import { ISplit } from '../dtos/types';
|
|
3
|
+
import { objectAssign } from '../utils/lang/objectAssign';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* This class provides a skeletal implementation of the ISplitsCacheAsync interface
|
|
@@ -7,14 +8,14 @@ import { ISplit } from '../dtos/types';
|
|
|
7
8
|
*/
|
|
8
9
|
export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
|
|
9
10
|
|
|
10
|
-
abstract addSplit(name: string, split:
|
|
11
|
-
abstract addSplits(entries: [string,
|
|
11
|
+
abstract addSplit(name: string, split: ISplit): Promise<boolean>
|
|
12
|
+
abstract addSplits(entries: [string, ISplit][]): Promise<boolean[] | void>
|
|
12
13
|
abstract removeSplits(names: string[]): Promise<boolean[] | void>
|
|
13
|
-
abstract getSplit(name: string): Promise<
|
|
14
|
-
abstract getSplits(names: string[]): Promise<Record<string,
|
|
14
|
+
abstract getSplit(name: string): Promise<ISplit | null>
|
|
15
|
+
abstract getSplits(names: string[]): Promise<Record<string, ISplit | null>>
|
|
15
16
|
abstract setChangeNumber(changeNumber: number): Promise<boolean | void>
|
|
16
17
|
abstract getChangeNumber(): Promise<number>
|
|
17
|
-
abstract getAll(): Promise<
|
|
18
|
+
abstract getAll(): Promise<ISplit[]>
|
|
18
19
|
abstract getSplitNames(): Promise<string[]>
|
|
19
20
|
abstract trafficTypeExists(trafficType: string): Promise<boolean>
|
|
20
21
|
abstract clear(): Promise<boolean | void>
|
|
@@ -40,23 +41,20 @@ export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
|
|
|
40
41
|
* @param {string} name
|
|
41
42
|
* @param {string} defaultTreatment
|
|
42
43
|
* @param {number} changeNumber
|
|
43
|
-
* @returns {Promise} a promise that is resolved once the split kill operation is performed. The fulfillment value is a boolean: `true` if the
|
|
44
|
+
* @returns {Promise} a promise that is resolved once the split kill operation is performed. The fulfillment value is a boolean: `true` if the operation successed updating the split or `false` if no split is updated,
|
|
44
45
|
* for instance, if the `changeNumber` is old, or if the split is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
|
|
45
46
|
* The promise will never be rejected.
|
|
46
47
|
*/
|
|
47
48
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise<boolean> {
|
|
48
49
|
return this.getSplit(name).then(split => {
|
|
49
50
|
|
|
50
|
-
if (split) {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
parsedSplit.changeNumber = changeNumber;
|
|
56
|
-
const newSplit = JSON.stringify(parsedSplit);
|
|
51
|
+
if (split && (!split.changeNumber || split.changeNumber < changeNumber)) {
|
|
52
|
+
const newSplit = objectAssign({}, split);
|
|
53
|
+
newSplit.killed = true;
|
|
54
|
+
newSplit.defaultTreatment = defaultTreatment;
|
|
55
|
+
newSplit.changeNumber = changeNumber;
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
}
|
|
57
|
+
return this.addSplit(name, newSplit);
|
|
60
58
|
}
|
|
61
59
|
return false;
|
|
62
60
|
}).catch(() => false);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ISplitsCacheSync } from './types';
|
|
2
2
|
import { ISplit } from '../dtos/types';
|
|
3
|
+
import { objectAssign } from '../utils/lang/objectAssign';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* This class provides a skeletal implementation of the ISplitsCacheSync interface
|
|
@@ -7,9 +8,9 @@ import { ISplit } from '../dtos/types';
|
|
|
7
8
|
*/
|
|
8
9
|
export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
9
10
|
|
|
10
|
-
abstract addSplit(name: string, split:
|
|
11
|
+
abstract addSplit(name: string, split: ISplit): boolean
|
|
11
12
|
|
|
12
|
-
addSplits(entries: [string,
|
|
13
|
+
addSplits(entries: [string, ISplit][]): boolean[] {
|
|
13
14
|
return entries.map(keyValuePair => this.addSplit(keyValuePair[0], keyValuePair[1]));
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -19,10 +20,10 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
|
19
20
|
return names.map(name => this.removeSplit(name));
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
abstract getSplit(name: string):
|
|
23
|
+
abstract getSplit(name: string): ISplit | null
|
|
23
24
|
|
|
24
|
-
getSplits(names: string[]): Record<string,
|
|
25
|
-
const splits: Record<string,
|
|
25
|
+
getSplits(names: string[]): Record<string, ISplit | null> {
|
|
26
|
+
const splits: Record<string, ISplit | null> = {};
|
|
26
27
|
names.forEach(name => {
|
|
27
28
|
splits[name] = this.getSplit(name);
|
|
28
29
|
});
|
|
@@ -33,8 +34,8 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
|
33
34
|
|
|
34
35
|
abstract getChangeNumber(): number
|
|
35
36
|
|
|
36
|
-
getAll():
|
|
37
|
-
return this.getSplitNames().map(key => this.getSplit(key) as
|
|
37
|
+
getAll(): ISplit[] {
|
|
38
|
+
return this.getSplitNames().map(key => this.getSplit(key) as ISplit);
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
abstract getSplitNames(): string[]
|
|
@@ -60,22 +61,19 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
|
60
61
|
* @param {string} name
|
|
61
62
|
* @param {string} defaultTreatment
|
|
62
63
|
* @param {number} changeNumber
|
|
63
|
-
* @returns {
|
|
64
|
+
* @returns {boolean} `true` if the operation successed updating the split, or `false` if no split is updated,
|
|
64
65
|
* for instance, if the `changeNumber` is old, or if the split is not found (e.g., `/splitchanges` hasn't been fetched yet), or if the storage fails to apply the update.
|
|
65
66
|
*/
|
|
66
67
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean {
|
|
67
68
|
const split = this.getSplit(name);
|
|
68
69
|
|
|
69
|
-
if (split) {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
parsedSplit.changeNumber = changeNumber;
|
|
75
|
-
const newSplit = JSON.stringify(parsedSplit);
|
|
70
|
+
if (split && (!split.changeNumber || split.changeNumber < changeNumber)) {
|
|
71
|
+
const newSplit = objectAssign({}, split);
|
|
72
|
+
newSplit.killed = true;
|
|
73
|
+
newSplit.defaultTreatment = defaultTreatment;
|
|
74
|
+
newSplit.changeNumber = changeNumber;
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
}
|
|
76
|
+
return this.addSplit(name, newSplit);
|
|
79
77
|
}
|
|
80
78
|
return false;
|
|
81
79
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { KeyBuilder } from './KeyBuilder';
|
|
2
2
|
import { IMetadata } from '../dtos/types';
|
|
3
3
|
import { Method } from '../sync/submitters/types';
|
|
4
|
+
import { MAX_LATENCY_BUCKET_COUNT } from './inMemory/TelemetryCacheInMemory';
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
+
const METHOD_NAMES: Record<Method, string> = {
|
|
6
7
|
t: 'treatment',
|
|
7
8
|
ts: 'treatments',
|
|
8
9
|
tc: 'treatmentWithConfig',
|
|
@@ -12,11 +13,17 @@ const methodNames: Record<Method, string> = {
|
|
|
12
13
|
|
|
13
14
|
export class KeyBuilderSS extends KeyBuilder {
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
latencyPrefix: string;
|
|
17
|
+
exceptionPrefix: string;
|
|
18
|
+
initPrefix: string;
|
|
19
|
+
private versionablePrefix: string;
|
|
16
20
|
|
|
17
21
|
constructor(prefix: string, metadata: IMetadata) {
|
|
18
22
|
super(prefix);
|
|
19
|
-
this.
|
|
23
|
+
this.latencyPrefix = `${this.prefix}.telemetry.latencies`;
|
|
24
|
+
this.exceptionPrefix = `${this.prefix}.telemetry.exceptions`;
|
|
25
|
+
this.initPrefix = `${this.prefix}.telemetry.init`;
|
|
26
|
+
this.versionablePrefix = `${metadata.s}/${metadata.n}/${metadata.i}`;
|
|
20
27
|
}
|
|
21
28
|
|
|
22
29
|
buildRegisteredSegmentsKey() {
|
|
@@ -27,6 +34,14 @@ export class KeyBuilderSS extends KeyBuilder {
|
|
|
27
34
|
return `${this.prefix}.impressions`;
|
|
28
35
|
}
|
|
29
36
|
|
|
37
|
+
buildImpressionsCountKey() {
|
|
38
|
+
return `${this.prefix}.impressions.count`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
buildUniqueKeysKey() {
|
|
42
|
+
return `${this.prefix}.uniquekeys`;
|
|
43
|
+
}
|
|
44
|
+
|
|
30
45
|
buildEventsKey() {
|
|
31
46
|
return `${this.prefix}.events`;
|
|
32
47
|
}
|
|
@@ -38,19 +53,56 @@ export class KeyBuilderSS extends KeyBuilder {
|
|
|
38
53
|
/* Telemetry keys */
|
|
39
54
|
|
|
40
55
|
buildLatencyKey(method: Method, bucket: number) {
|
|
41
|
-
return `${this.
|
|
56
|
+
return `${this.latencyPrefix}::${this.versionablePrefix}/${METHOD_NAMES[method]}/${bucket}`;
|
|
42
57
|
}
|
|
43
58
|
|
|
44
59
|
buildExceptionKey(method: Method) {
|
|
45
|
-
return `${this.
|
|
60
|
+
return `${this.exceptionPrefix}::${this.versionablePrefix}/${METHOD_NAMES[method]}`;
|
|
46
61
|
}
|
|
47
62
|
|
|
48
63
|
buildInitKey() {
|
|
49
|
-
return `${this.
|
|
64
|
+
return `${this.initPrefix}::${this.versionablePrefix}`;
|
|
50
65
|
}
|
|
51
66
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Used by consumer methods of TelemetryCacheInRedis and TelemetryCachePluggable
|
|
70
|
+
|
|
71
|
+
const REVERSE_METHOD_NAMES = Object.keys(METHOD_NAMES).reduce((acc, key) => {
|
|
72
|
+
acc[METHOD_NAMES[key as Method]] = key as Method;
|
|
73
|
+
return acc;
|
|
74
|
+
}, {} as Record<string, Method>);
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
export function parseMetadata(field: string): [metadata: string] | string {
|
|
78
|
+
const parts = field.split('/');
|
|
79
|
+
if (parts.length !== 3) return `invalid subsection count. Expected 3, got: ${parts.length}`;
|
|
80
|
+
|
|
81
|
+
const [s /* metadata.s */, n /* metadata.n */, i /* metadata.i */] = parts;
|
|
82
|
+
return [JSON.stringify({ s, n, i })];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function parseExceptionField(field: string): [metadata: string, method: Method] | string {
|
|
86
|
+
const parts = field.split('/');
|
|
87
|
+
if (parts.length !== 4) return `invalid subsection count. Expected 4, got: ${parts.length}`;
|
|
88
|
+
|
|
89
|
+
const [s /* metadata.s */, n /* metadata.n */, i /* metadata.i */, m] = parts;
|
|
90
|
+
const method = REVERSE_METHOD_NAMES[m];
|
|
91
|
+
if (!method) return `unknown method '${m}'`;
|
|
92
|
+
|
|
93
|
+
return [JSON.stringify({ s, n, i }), method];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function parseLatencyField(field: string): [metadata: string, method: Method, bucket: number] | string {
|
|
97
|
+
const parts = field.split('/');
|
|
98
|
+
if (parts.length !== 5) return `invalid subsection count. Expected 5, got: ${parts.length}`;
|
|
99
|
+
|
|
100
|
+
const [s /* metadata.s */, n /* metadata.n */, i /* metadata.i */, m, b] = parts;
|
|
101
|
+
const method = REVERSE_METHOD_NAMES[m];
|
|
102
|
+
if (!method) return `unknown method '${m}'`;
|
|
103
|
+
|
|
104
|
+
const bucket = parseInt(b);
|
|
105
|
+
if (isNaN(bucket) || bucket >= MAX_LATENCY_BUCKET_COUNT) return `invalid bucket. Expected a number between 0 and ${MAX_LATENCY_BUCKET_COUNT - 1}, got: ${b}`;
|
|
55
106
|
|
|
107
|
+
return [JSON.stringify({ s, n, i }), method, bucket];
|
|
56
108
|
}
|
|
@@ -39,7 +39,7 @@ export function dataLoaderFactory(preloadedData: SplitIO.PreloadedData): DataLoa
|
|
|
39
39
|
storage.splits.setChangeNumber(since);
|
|
40
40
|
|
|
41
41
|
// splitsData in an object where the property is the split name and the pertaining value is a stringified json of its data
|
|
42
|
-
storage.splits.addSplits(Object.keys(splitsData).map(splitName =>
|
|
42
|
+
storage.splits.addSplits(Object.keys(splitsData).map(splitName => JSON.parse(splitsData[splitName])));
|
|
43
43
|
|
|
44
44
|
// add mySegments data
|
|
45
45
|
let mySegmentsData = preloadedData.mySegmentsData && preloadedData.mySegmentsData[userId];
|
|
@@ -38,7 +38,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
38
38
|
else localStorage.removeItem(key);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
private _decrementCounts(split: ISplit) {
|
|
41
|
+
private _decrementCounts(split: ISplit | null) {
|
|
42
42
|
try {
|
|
43
43
|
if (split) {
|
|
44
44
|
if (split.trafficTypeName) {
|
|
@@ -99,18 +99,16 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
99
99
|
this.hasSync = false;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
addSplit(name: string, split:
|
|
102
|
+
addSplit(name: string, split: ISplit) {
|
|
103
103
|
try {
|
|
104
104
|
const splitKey = this.keys.buildSplitKey(name);
|
|
105
105
|
const splitFromLocalStorage = localStorage.getItem(splitKey);
|
|
106
106
|
const previousSplit = splitFromLocalStorage ? JSON.parse(splitFromLocalStorage) : null;
|
|
107
107
|
this._decrementCounts(previousSplit);
|
|
108
108
|
|
|
109
|
-
localStorage.setItem(splitKey, split);
|
|
109
|
+
localStorage.setItem(splitKey, JSON.stringify(split));
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
this._incrementCounts(parsedSplit);
|
|
111
|
+
this._incrementCounts(split);
|
|
114
112
|
|
|
115
113
|
return true;
|
|
116
114
|
} catch (e) {
|
|
@@ -124,8 +122,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
124
122
|
const split = this.getSplit(name);
|
|
125
123
|
localStorage.removeItem(this.keys.buildSplitKey(name));
|
|
126
124
|
|
|
127
|
-
|
|
128
|
-
this._decrementCounts(parsedSplit);
|
|
125
|
+
this._decrementCounts(split);
|
|
129
126
|
|
|
130
127
|
return true;
|
|
131
128
|
} catch (e) {
|
|
@@ -135,7 +132,8 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
135
132
|
}
|
|
136
133
|
|
|
137
134
|
getSplit(name: string) {
|
|
138
|
-
|
|
135
|
+
const item = localStorage.getItem(this.keys.buildSplitKey(name));
|
|
136
|
+
return item && JSON.parse(item);
|
|
139
137
|
}
|
|
140
138
|
|
|
141
139
|
setChangeNumber(changeNumber: number): boolean {
|
|
@@ -184,7 +182,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
184
182
|
return n;
|
|
185
183
|
}
|
|
186
184
|
|
|
187
|
-
getSplitNames() {
|
|
185
|
+
getSplitNames(): string[] {
|
|
188
186
|
const len = localStorage.length;
|
|
189
187
|
const accum = [];
|
|
190
188
|
|
|
@@ -231,7 +229,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
231
229
|
|
|
232
230
|
/**
|
|
233
231
|
* Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
|
|
234
|
-
* Clean operation (clear) also updates `lastUpdated` timestamp with current time.
|
|
235
232
|
*
|
|
236
233
|
* @param {number | undefined} expirationTimestamp if the value is not a number, data will not be cleaned
|
|
237
234
|
*/
|
|
@@ -12,8 +12,9 @@ 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 {
|
|
15
|
+
import { NONE, STORAGE_LOCALSTORAGE } from '../../utils/constants';
|
|
16
16
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
|
|
17
|
+
import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
|
|
17
18
|
|
|
18
19
|
export interface InLocalStorageOptions {
|
|
19
20
|
prefix?: string
|
|
@@ -44,7 +45,8 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
44
45
|
impressions: new ImpressionsCacheInMemory(params.impressionsQueueSize),
|
|
45
46
|
impressionCounts: params.optimize ? new ImpressionCountsCacheInMemory() : undefined,
|
|
46
47
|
events: new EventsCacheInMemory(params.eventsQueueSize),
|
|
47
|
-
telemetry:
|
|
48
|
+
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory() : undefined,
|
|
49
|
+
uniqueKeys: params.impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
|
|
48
50
|
|
|
49
51
|
destroy() {
|
|
50
52
|
this.splits = new SplitsCacheInMemory();
|
|
@@ -52,6 +54,7 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
52
54
|
this.impressions.clear();
|
|
53
55
|
this.impressionCounts && this.impressionCounts.clear();
|
|
54
56
|
this.events.clear();
|
|
57
|
+
this.uniqueKeys?.clear();
|
|
55
58
|
},
|
|
56
59
|
|
|
57
60
|
// When using shared instanciation with MEMORY we reuse everything but segments (they are customer per key).
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { truncateTimeFrame } from '../../utils/time';
|
|
2
|
+
import { DEFAULT_CACHE_SIZE } from '../inRedis/constants';
|
|
2
3
|
import { IImpressionCountsCacheSync } from '../types';
|
|
3
4
|
|
|
4
5
|
export class ImpressionCountsCacheInMemory implements IImpressionCountsCacheSync {
|
|
5
|
-
|
|
6
|
+
protected cache: Record<string, number> = {};
|
|
7
|
+
private readonly maxStorage: number;
|
|
8
|
+
protected onFullQueue?: () => void;
|
|
9
|
+
private cacheSize = 0;
|
|
10
|
+
|
|
11
|
+
constructor(impressionCountsCacheSize = DEFAULT_CACHE_SIZE) {
|
|
12
|
+
this.maxStorage = impressionCountsCacheSize;
|
|
13
|
+
}
|
|
6
14
|
|
|
7
15
|
/**
|
|
8
16
|
* Builds key to be stored in the cache with the featureName and the timeFrame truncated.
|
|
@@ -18,6 +26,13 @@ export class ImpressionCountsCacheInMemory implements IImpressionCountsCacheSync
|
|
|
18
26
|
const key = this._makeKey(featureName, timeFrame);
|
|
19
27
|
const currentAmount = this.cache[key];
|
|
20
28
|
this.cache[key] = currentAmount ? currentAmount + amount : amount;
|
|
29
|
+
if (this.onFullQueue) {
|
|
30
|
+
this.cacheSize = this.cacheSize + amount;
|
|
31
|
+
if (this.cacheSize >= this.maxStorage) {
|
|
32
|
+
this.onFullQueue();
|
|
33
|
+
this.cacheSize = 0;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
21
36
|
}
|
|
22
37
|
|
|
23
38
|
|
|
@@ -4,8 +4,9 @@ import { ImpressionsCacheInMemory } from './ImpressionsCacheInMemory';
|
|
|
4
4
|
import { EventsCacheInMemory } from './EventsCacheInMemory';
|
|
5
5
|
import { IStorageFactoryParams, IStorageSync } from '../types';
|
|
6
6
|
import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
|
|
7
|
-
import {
|
|
8
|
-
import { TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
7
|
+
import { DEBUG, NONE, STORAGE_MEMORY } from '../../utils/constants';
|
|
8
|
+
import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
9
|
+
import { UniqueKeysCacheInMemory } from './UniqueKeysCacheInMemory';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* InMemory storage factory for standalone server-side SplitFactory
|
|
@@ -18,9 +19,10 @@ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageS
|
|
|
18
19
|
splits: new SplitsCacheInMemory(),
|
|
19
20
|
segments: new SegmentsCacheInMemory(),
|
|
20
21
|
impressions: new ImpressionsCacheInMemory(params.impressionsQueueSize),
|
|
21
|
-
impressionCounts: params.
|
|
22
|
+
impressionCounts: params.impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
|
|
22
23
|
events: new EventsCacheInMemory(params.eventsQueueSize),
|
|
23
|
-
telemetry: params
|
|
24
|
+
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory() : undefined,
|
|
25
|
+
uniqueKeys: params.impressionsMode === NONE ? new UniqueKeysCacheInMemory() : undefined,
|
|
24
26
|
|
|
25
27
|
// When using MEMORY we should clean all the caches to leave them empty
|
|
26
28
|
destroy() {
|
|
@@ -29,6 +31,7 @@ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageS
|
|
|
29
31
|
this.impressions.clear();
|
|
30
32
|
this.impressionCounts && this.impressionCounts.clear();
|
|
31
33
|
this.events.clear();
|
|
34
|
+
this.uniqueKeys?.clear();
|
|
32
35
|
}
|
|
33
36
|
};
|
|
34
37
|
}
|
|
@@ -4,8 +4,9 @@ import { ImpressionsCacheInMemory } from './ImpressionsCacheInMemory';
|
|
|
4
4
|
import { EventsCacheInMemory } from './EventsCacheInMemory';
|
|
5
5
|
import { IStorageSync, IStorageFactoryParams } from '../types';
|
|
6
6
|
import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
|
|
7
|
-
import {
|
|
7
|
+
import { DEBUG, NONE, STORAGE_MEMORY } from '../../utils/constants';
|
|
8
8
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
9
|
+
import { UniqueKeysCacheInMemoryCS } from './UniqueKeysCacheInMemoryCS';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* InMemory storage factory for standalone client-side SplitFactory
|
|
@@ -18,9 +19,10 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
18
19
|
splits: new SplitsCacheInMemory(),
|
|
19
20
|
segments: new MySegmentsCacheInMemory(),
|
|
20
21
|
impressions: new ImpressionsCacheInMemory(params.impressionsQueueSize),
|
|
21
|
-
impressionCounts: params.
|
|
22
|
+
impressionCounts: params.impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
|
|
22
23
|
events: new EventsCacheInMemory(params.eventsQueueSize),
|
|
23
|
-
telemetry:
|
|
24
|
+
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory() : undefined,
|
|
25
|
+
uniqueKeys: params.impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
|
|
24
26
|
|
|
25
27
|
// When using MEMORY we should clean all the caches to leave them empty
|
|
26
28
|
destroy() {
|
|
@@ -29,6 +31,7 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
29
31
|
this.impressions.clear();
|
|
30
32
|
this.impressionCounts && this.impressionCounts.clear();
|
|
31
33
|
this.events.clear();
|
|
34
|
+
this.uniqueKeys?.clear();
|
|
32
35
|
},
|
|
33
36
|
|
|
34
37
|
// When using shared instanciation with MEMORY we reuse everything but segments (they are unique per key)
|
|
@@ -8,7 +8,7 @@ import { isFiniteNumber } from '../../utils/lang';
|
|
|
8
8
|
*/
|
|
9
9
|
export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
10
10
|
|
|
11
|
-
private splitsCache: Record<string,
|
|
11
|
+
private splitsCache: Record<string, ISplit> = {};
|
|
12
12
|
private ttCache: Record<string, number> = {};
|
|
13
13
|
private changeNumber: number = -1;
|
|
14
14
|
private splitsWithSegmentsCount: number = 0;
|
|
@@ -20,10 +20,9 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
20
20
|
this.splitsWithSegmentsCount = 0;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
addSplit(name: string, split:
|
|
24
|
-
const
|
|
25
|
-
if (
|
|
26
|
-
const previousSplit: ISplit = JSON.parse(splitFromMemory);
|
|
23
|
+
addSplit(name: string, split: ISplit): boolean {
|
|
24
|
+
const previousSplit = this.getSplit(name);
|
|
25
|
+
if (previousSplit) { // We had this Split already
|
|
27
26
|
|
|
28
27
|
if (previousSplit.trafficTypeName) {
|
|
29
28
|
const previousTtName = previousSplit.trafficTypeName;
|
|
@@ -36,20 +35,18 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
36
35
|
}
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (parsedSplit) {
|
|
38
|
+
if (split) {
|
|
42
39
|
// Store the Split.
|
|
43
40
|
this.splitsCache[name] = split;
|
|
44
41
|
// Update TT cache
|
|
45
|
-
const ttName =
|
|
42
|
+
const ttName = split.trafficTypeName;
|
|
46
43
|
if (ttName) { // safeguard
|
|
47
44
|
if (!this.ttCache[ttName]) this.ttCache[ttName] = 0;
|
|
48
45
|
this.ttCache[ttName]++;
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
// Add to segments count for the new version of the Split
|
|
52
|
-
if (usesSegments(
|
|
49
|
+
if (usesSegments(split)) this.splitsWithSegmentsCount++;
|
|
53
50
|
|
|
54
51
|
return true;
|
|
55
52
|
} else {
|
|
@@ -63,8 +60,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
63
60
|
// Delete the Split
|
|
64
61
|
delete this.splitsCache[name];
|
|
65
62
|
|
|
66
|
-
const
|
|
67
|
-
const ttName = parsedSplit.trafficTypeName;
|
|
63
|
+
const ttName = split.trafficTypeName;
|
|
68
64
|
|
|
69
65
|
if (ttName) { // safeguard
|
|
70
66
|
this.ttCache[ttName]--; // Update tt cache
|
|
@@ -72,7 +68,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
72
68
|
}
|
|
73
69
|
|
|
74
70
|
// Update the segments count.
|
|
75
|
-
if (usesSegments(
|
|
71
|
+
if (usesSegments(split)) this.splitsWithSegmentsCount--;
|
|
76
72
|
|
|
77
73
|
return true;
|
|
78
74
|
} else {
|
|
@@ -80,7 +76,7 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
|
|
|
80
76
|
}
|
|
81
77
|
}
|
|
82
78
|
|
|
83
|
-
getSplit(name: string):
|
|
79
|
+
getSplit(name: string): ISplit | null {
|
|
84
80
|
return this.splitsCache[name] || null;
|
|
85
81
|
}
|
|
86
82
|
|
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies } from '../../sync/submitters/types';
|
|
2
|
+
import { LOCALHOST_MODE } from '../../utils/constants';
|
|
2
3
|
import { findLatencyIndex } from '../findLatencyIndex';
|
|
3
|
-
import { ITelemetryCacheSync } from '../types';
|
|
4
|
+
import { IStorageFactoryParams, ITelemetryCacheSync } from '../types';
|
|
4
5
|
|
|
5
6
|
const MAX_STREAMING_EVENTS = 20;
|
|
6
7
|
const MAX_TAGS = 10;
|
|
8
|
+
export const MAX_LATENCY_BUCKET_COUNT = 23;
|
|
7
9
|
|
|
8
|
-
function newBuckets() {
|
|
9
|
-
// MAX_LATENCY_BUCKET_COUNT (length) is 23
|
|
10
|
+
export function newBuckets() {
|
|
11
|
+
// MAX_LATENCY_BUCKET_COUNT (length) is 23
|
|
12
|
+
// Not using Array.fill for old browsers compatibility
|
|
10
13
|
return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
const ACCEPTANCE_RANGE = 0.001;
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
|
-
*
|
|
19
|
+
* Record telemetry if mode is not localhost.
|
|
20
|
+
* All factory instances track telemetry on server-side, and 0.1% on client-side.
|
|
17
21
|
*/
|
|
18
|
-
export function shouldRecordTelemetry() {
|
|
19
|
-
return Math.random() <= ACCEPTANCE_RANGE;
|
|
22
|
+
export function shouldRecordTelemetry(params: IStorageFactoryParams) {
|
|
23
|
+
return params.mode !== LOCALHOST_MODE && (params.matchingKey === undefined || Math.random() <= ACCEPTANCE_RANGE);
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
export class TelemetryCacheInMemory implements ITelemetryCacheSync {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { IUniqueKeysCacheBase } from '../types';
|
|
2
|
+
import { ISet, setToArray, _Set } from '../../utils/lang/sets';
|
|
3
|
+
import { UniqueKeysPayloadSs } from '../../sync/submitters/types';
|
|
4
|
+
import { DEFAULT_CACHE_SIZE } from '../inRedis/constants';
|
|
5
|
+
|
|
6
|
+
export class UniqueKeysCacheInMemory implements IUniqueKeysCacheBase {
|
|
7
|
+
|
|
8
|
+
protected onFullQueue?: () => void;
|
|
9
|
+
private readonly maxStorage: number;
|
|
10
|
+
private uniqueTrackerSize = 0;
|
|
11
|
+
protected uniqueKeysTracker: { [keys: string]: ISet<string> };
|
|
12
|
+
|
|
13
|
+
constructor(uniqueKeysQueueSize = DEFAULT_CACHE_SIZE) {
|
|
14
|
+
this.maxStorage = uniqueKeysQueueSize;
|
|
15
|
+
this.uniqueKeysTracker = {};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setOnFullQueueCb(cb: () => void) {
|
|
19
|
+
this.onFullQueue = cb;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Store unique keys in sequential order
|
|
24
|
+
* key: string = feature name.
|
|
25
|
+
* value: Set<string> = set of unique keys.
|
|
26
|
+
*/
|
|
27
|
+
track(key: string, featureName: string) {
|
|
28
|
+
if (!this.uniqueKeysTracker[featureName]) this.uniqueKeysTracker[featureName] = new _Set();
|
|
29
|
+
const tracker = this.uniqueKeysTracker[featureName];
|
|
30
|
+
if (!tracker.has(key)) {
|
|
31
|
+
tracker.add(key);
|
|
32
|
+
this.uniqueTrackerSize++;
|
|
33
|
+
}
|
|
34
|
+
if (this.uniqueTrackerSize >= this.maxStorage && this.onFullQueue) {
|
|
35
|
+
this.uniqueTrackerSize = 0;
|
|
36
|
+
this.onFullQueue();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Clear the data stored on the cache.
|
|
42
|
+
*/
|
|
43
|
+
clear() {
|
|
44
|
+
this.uniqueKeysTracker = {};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Pop the collected data, used as payload for posting.
|
|
49
|
+
*/
|
|
50
|
+
pop() {
|
|
51
|
+
const data = this.uniqueKeysTracker;
|
|
52
|
+
this.uniqueKeysTracker = {};
|
|
53
|
+
return this.fromUniqueKeysCollector(data);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if the cache is empty.
|
|
58
|
+
*/
|
|
59
|
+
isEmpty() {
|
|
60
|
+
return Object.keys(this.uniqueKeysTracker).length === 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Converts `uniqueKeys` data from cache into request payload for SS.
|
|
65
|
+
*/
|
|
66
|
+
private fromUniqueKeysCollector(uniqueKeys: { [featureName: string]: ISet<string> }): UniqueKeysPayloadSs {
|
|
67
|
+
const payload = [];
|
|
68
|
+
const featureNames = Object.keys(uniqueKeys);
|
|
69
|
+
for (let i = 0; i < featureNames.length; i++) {
|
|
70
|
+
const featureName = featureNames[i];
|
|
71
|
+
const featureKeys = setToArray(uniqueKeys[featureName]);
|
|
72
|
+
const uniqueKeysPayload = {
|
|
73
|
+
f: featureName,
|
|
74
|
+
ks: featureKeys
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
payload.push(uniqueKeysPayload);
|
|
78
|
+
}
|
|
79
|
+
return { keys: payload };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
}
|