@splitsoftware/splitio-commons 1.6.2-rc.1 → 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/sdkClient/client.js +19 -7
- package/cjs/sdkClient/sdkClient.js +3 -1
- package/cjs/sdkFactory/index.js +15 -6
- package/cjs/sdkManager/index.js +3 -11
- package/cjs/services/splitApi.js +6 -6
- 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/telemetrySubmitter.js +8 -4
- package/cjs/sync/submitters/uniqueKeysSubmitter.js +16 -59
- package/cjs/trackers/impressionsTracker.js +17 -15
- package/cjs/trackers/strategy/strategyNone.js +1 -1
- package/cjs/trackers/strategy/strategyOptimized.js +2 -1
- package/cjs/trackers/telemetryTracker.js +6 -0
- package/cjs/trackers/uniqueKeysTracker.js +11 -42
- package/cjs/utils/constants/index.js +3 -2
- package/cjs/utils/lang/maps.js +15 -7
- package/cjs/utils/redis/RedisMock.js +31 -0
- package/cjs/utils/settingsValidation/index.js +0 -3
- package/esm/consent/sdkUserConsent.js +2 -2
- package/esm/evaluator/index.js +15 -16
- package/esm/integrations/ga/GaToSplit.js +8 -5
- package/esm/sdkClient/client.js +19 -7
- package/esm/sdkClient/sdkClient.js +3 -1
- package/esm/sdkFactory/index.js +16 -7
- package/esm/sdkManager/index.js +3 -11
- package/esm/services/splitApi.js +6 -6
- 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/telemetrySubmitter.js +9 -5
- package/esm/sync/submitters/uniqueKeysSubmitter.js +15 -56
- package/esm/trackers/impressionsTracker.js +17 -15
- package/esm/trackers/strategy/strategyNone.js +1 -1
- package/esm/trackers/strategy/strategyOptimized.js +2 -1
- package/esm/trackers/telemetryTracker.js +6 -0
- package/esm/trackers/uniqueKeysTracker.js +11 -42
- package/esm/utils/constants/index.js +1 -0
- package/esm/utils/lang/maps.js +15 -7
- package/esm/utils/redis/RedisMock.js +28 -0
- package/esm/utils/settingsValidation/index.js +0 -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/logger/.DS_Store +0 -0
- package/src/sdkClient/client.ts +21 -8
- package/src/sdkClient/sdkClient.ts +3 -1
- package/src/sdkFactory/index.ts +17 -7
- package/src/sdkManager/index.ts +3 -12
- package/src/services/splitApi.ts +6 -6
- package/src/services/types.ts +2 -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 +38 -30
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +5 -6
- package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -2
- package/src/sync/submitters/telemetrySubmitter.ts +15 -8
- package/src/sync/submitters/types.ts +18 -6
- package/src/sync/submitters/uniqueKeysSubmitter.ts +18 -61
- package/src/trackers/impressionsTracker.ts +16 -15
- package/src/trackers/strategy/strategyNone.ts +1 -1
- package/src/trackers/strategy/strategyOptimized.ts +1 -1
- package/src/trackers/telemetryTracker.ts +7 -2
- package/src/trackers/types.ts +9 -7
- package/src/trackers/uniqueKeysTracker.ts +15 -47
- package/src/types.ts +0 -1
- package/src/utils/constants/index.ts +1 -0
- package/src/utils/lang/maps.ts +20 -8
- package/src/utils/redis/RedisMock.ts +33 -0
- package/src/utils/settingsValidation/index.ts +1 -4
- package/types/integrations/types.d.ts +2 -1
- package/types/services/types.d.ts +2 -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 +35 -35
- 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 +12 -6
- package/types/sync/submitters/uniqueKeysSubmitter.d.ts +0 -14
- package/types/trackers/types.d.ts +9 -11
- package/types/trackers/uniqueKeysTracker.d.ts +3 -3
- package/types/types.d.ts +0 -1
- package/types/utils/constants/index.d.ts +1 -0
- package/types/utils/lang/maps.d.ts +6 -2
- package/types/utils/redis/RedisMock.d.ts +4 -0
- package/types/utils/settingsValidation/index.d.ts +0 -1
- package/types/sdkClient/types.d.ts +0 -18
- package/types/storages/inMemory/CountsCacheInMemory.d.ts +0 -20
- package/types/storages/inMemory/LatenciesCacheInMemory.d.ts +0 -20
- package/types/storages/inRedis/CountsCacheInRedis.d.ts +0 -9
- package/types/storages/inRedis/LatenciesCacheInRedis.d.ts +0 -9
- package/types/sync/offline/LocalhostFromFile.d.ts +0 -2
- package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +0 -2
- 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/syncTaskComposite.d.ts +0 -5
- package/types/trackers/filter/bloomFilter.d.ts +0 -10
- package/types/trackers/filter/dictionaryFilter.d.ts +0 -8
- package/types/trackers/filter/types.d.ts +0 -5
- package/types/utils/timeTracker/index.d.ts +0 -70
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { IUniqueKeysCacheBase } from '../types';
|
|
2
|
+
import { ISet, setToArray, _Set } from '../../utils/lang/sets';
|
|
3
|
+
import { UniqueKeysPayloadCs } from '../../sync/submitters/types';
|
|
4
|
+
import { DEFAULT_CACHE_SIZE } from '../inRedis/constants';
|
|
5
|
+
|
|
6
|
+
export class UniqueKeysCacheInMemoryCS implements IUniqueKeysCacheBase {
|
|
7
|
+
|
|
8
|
+
private onFullQueue?: () => void;
|
|
9
|
+
private readonly maxStorage: number;
|
|
10
|
+
private uniqueTrackerSize = 0;
|
|
11
|
+
private uniqueKeysTracker: { [keys: string]: ISet<string> };
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* @param impressionsQueueSize number of queued impressions to call onFullQueueCb.
|
|
16
|
+
* Default value is 0, that means no maximum value, in case we want to avoid this being triggered.
|
|
17
|
+
*/
|
|
18
|
+
constructor(uniqueKeysQueueSize = DEFAULT_CACHE_SIZE) {
|
|
19
|
+
this.maxStorage = uniqueKeysQueueSize;
|
|
20
|
+
this.uniqueKeysTracker = {};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
setOnFullQueueCb(cb: () => void) {
|
|
24
|
+
this.onFullQueue = cb;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Store unique keys in sequential order
|
|
29
|
+
* key: string = key.
|
|
30
|
+
* value: HashSet<string> = set of split names.
|
|
31
|
+
*/
|
|
32
|
+
track(key: string, featureName: string) {
|
|
33
|
+
|
|
34
|
+
if (!this.uniqueKeysTracker[key]) this.uniqueKeysTracker[key] = new _Set();
|
|
35
|
+
const tracker = this.uniqueKeysTracker[key];
|
|
36
|
+
if (!tracker.has(featureName)) {
|
|
37
|
+
tracker.add(featureName);
|
|
38
|
+
this.uniqueTrackerSize++;
|
|
39
|
+
}
|
|
40
|
+
if (this.uniqueTrackerSize >= this.maxStorage && this.onFullQueue) {
|
|
41
|
+
this.uniqueTrackerSize = 0;
|
|
42
|
+
this.onFullQueue();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Clear the data stored on the cache.
|
|
48
|
+
*/
|
|
49
|
+
clear() {
|
|
50
|
+
this.uniqueKeysTracker = {};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Pop the collected data, used as payload for posting.
|
|
55
|
+
*/
|
|
56
|
+
pop() {
|
|
57
|
+
const data = this.uniqueKeysTracker;
|
|
58
|
+
this.uniqueKeysTracker = {};
|
|
59
|
+
return this.fromUniqueKeysCollector(data);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Check if the cache is empty.
|
|
64
|
+
*/
|
|
65
|
+
isEmpty() {
|
|
66
|
+
return Object.keys(this.uniqueKeysTracker).length === 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Converts `uniqueKeys` data from cache into request payload.
|
|
71
|
+
*/
|
|
72
|
+
private fromUniqueKeysCollector(uniqueKeys: { [featureName: string]: ISet<string> }): UniqueKeysPayloadCs {
|
|
73
|
+
const payload = [];
|
|
74
|
+
const featureKeys = Object.keys(uniqueKeys);
|
|
75
|
+
for (let k = 0; k < featureKeys.length; k++) {
|
|
76
|
+
const featureKey = featureKeys[k];
|
|
77
|
+
const featureNames = setToArray(uniqueKeys[featureKey]);
|
|
78
|
+
const uniqueKeysPayload = {
|
|
79
|
+
k: featureKey,
|
|
80
|
+
fs: featureNames
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
payload.push(uniqueKeysPayload);
|
|
84
|
+
}
|
|
85
|
+
return { keys: payload };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
|
@@ -59,7 +59,7 @@ export class EventsCacheInRedis implements IEventsCacheAsync {
|
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Pop the given number of events from the storage.
|
|
62
|
-
* The returned promise rejects if the
|
|
62
|
+
* The returned promise rejects if the redis operation fails.
|
|
63
63
|
*
|
|
64
64
|
* NOTE: this method doesn't take into account MAX_EVENT_SIZE or MAX_QUEUE_BYTE_SIZE limits.
|
|
65
65
|
* It is the submitter responsability to handle that.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Redis } from 'ioredis';
|
|
2
|
+
import { ILogger } from '../../logger/types';
|
|
3
|
+
import { ImpressionCountsCacheInMemory } from '../inMemory/ImpressionCountsCacheInMemory';
|
|
4
|
+
import { LOG_PREFIX, REFRESH_RATE, TTL_REFRESH } from './constants';
|
|
5
|
+
|
|
6
|
+
export class ImpressionCountsCacheInRedis extends ImpressionCountsCacheInMemory {
|
|
7
|
+
|
|
8
|
+
private readonly log: ILogger;
|
|
9
|
+
private readonly key: string;
|
|
10
|
+
private readonly redis: Redis;
|
|
11
|
+
private readonly refreshRate: number;
|
|
12
|
+
private intervalId: any;
|
|
13
|
+
|
|
14
|
+
constructor(log: ILogger, key: string, redis: Redis, impressionCountsCacheSize?: number, refreshRate = REFRESH_RATE) {
|
|
15
|
+
super(impressionCountsCacheSize);
|
|
16
|
+
this.log = log;
|
|
17
|
+
this.key = key;
|
|
18
|
+
this.redis = redis;
|
|
19
|
+
this.refreshRate = refreshRate;
|
|
20
|
+
this.onFullQueue = () => { this.postImpressionCountsInRedis(); };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private postImpressionCountsInRedis(){
|
|
24
|
+
const counts = this.pop();
|
|
25
|
+
const keys = Object.keys(counts);
|
|
26
|
+
if (!keys.length) return Promise.resolve(false);
|
|
27
|
+
|
|
28
|
+
const pipeline = this.redis.pipeline();
|
|
29
|
+
keys.forEach(key => {
|
|
30
|
+
pipeline.hincrby(this.key, key, counts[key]);
|
|
31
|
+
});
|
|
32
|
+
return pipeline.exec()
|
|
33
|
+
.then(data => {
|
|
34
|
+
// If this is the creation of the key on Redis, set the expiration for it in 3600 seconds.
|
|
35
|
+
if (data.length && data.length === keys.length) {
|
|
36
|
+
return this.redis.expire(this.key, TTL_REFRESH);
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
.catch(err => {
|
|
40
|
+
this.log.error(`${LOG_PREFIX}Error in impression counts pipeline: ${err}.`);
|
|
41
|
+
return false;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
start() {
|
|
46
|
+
this.intervalId = setInterval(this.postImpressionCountsInRedis.bind(this), this.refreshRate);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
stop() {
|
|
50
|
+
clearInterval(this.intervalId);
|
|
51
|
+
return this.postImpressionCountsInRedis();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -65,22 +65,22 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
65
65
|
* The returned promise is resolved when the operation success
|
|
66
66
|
* or rejected if it fails (e.g., redis operation fails)
|
|
67
67
|
*/
|
|
68
|
-
addSplit(name: string, split:
|
|
68
|
+
addSplit(name: string, split: ISplit): Promise<boolean> {
|
|
69
69
|
const splitKey = this.keys.buildSplitKey(name);
|
|
70
70
|
return this.redis.get(splitKey).then(splitFromStorage => {
|
|
71
71
|
|
|
72
72
|
// handling parsing errors
|
|
73
|
-
let parsedPreviousSplit,
|
|
73
|
+
let parsedPreviousSplit, newStringifiedSplit;
|
|
74
74
|
try {
|
|
75
75
|
parsedPreviousSplit = splitFromStorage ? JSON.parse(splitFromStorage) : undefined;
|
|
76
|
-
|
|
76
|
+
newStringifiedSplit = JSON.stringify(split);
|
|
77
77
|
} catch (e) {
|
|
78
78
|
throw new Error('Error parsing split definition: ' + e);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
return Promise.all([
|
|
82
|
-
this.redis.set(splitKey,
|
|
83
|
-
this._incrementCounts(
|
|
82
|
+
this.redis.set(splitKey, newStringifiedSplit),
|
|
83
|
+
this._incrementCounts(split),
|
|
84
84
|
// If it's an update, we decrement the traffic type of the existing split,
|
|
85
85
|
parsedPreviousSplit && this._decrementCounts(parsedPreviousSplit)
|
|
86
86
|
]);
|
|
@@ -92,7 +92,7 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
92
92
|
* The returned promise is resolved when the operation success
|
|
93
93
|
* or rejected if it fails (e.g., redis operation fails)
|
|
94
94
|
*/
|
|
95
|
-
addSplits(entries: [string,
|
|
95
|
+
addSplits(entries: [string, ISplit][]): Promise<boolean[]> {
|
|
96
96
|
return Promise.all(entries.map(keyValuePair => this.addSplit(keyValuePair[0], keyValuePair[1])));
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -104,8 +104,7 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
104
104
|
removeSplit(name: string): Promise<number> {
|
|
105
105
|
return this.getSplit(name).then((split) => {
|
|
106
106
|
if (split) {
|
|
107
|
-
|
|
108
|
-
this._decrementCounts(parsedSplit);
|
|
107
|
+
this._decrementCounts(split);
|
|
109
108
|
}
|
|
110
109
|
return this.redis.del(this.keys.buildSplitKey(name));
|
|
111
110
|
});
|
|
@@ -124,14 +123,15 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
124
123
|
* Get split definition or null if it's not defined.
|
|
125
124
|
* Returned promise is rejected if redis operation fails.
|
|
126
125
|
*/
|
|
127
|
-
getSplit(name: string): Promise<
|
|
126
|
+
getSplit(name: string): Promise<ISplit | null> {
|
|
128
127
|
if (this.redisError) {
|
|
129
128
|
this.log.error(LOG_PREFIX + this.redisError);
|
|
130
129
|
|
|
131
130
|
return Promise.reject(this.redisError);
|
|
132
131
|
}
|
|
133
132
|
|
|
134
|
-
return this.redis.get(this.keys.buildSplitKey(name))
|
|
133
|
+
return this.redis.get(this.keys.buildSplitKey(name))
|
|
134
|
+
.then(maybeSplit => maybeSplit && JSON.parse(maybeSplit));
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
/**
|
|
@@ -169,10 +169,13 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
169
169
|
* @TODO we need to benchmark which is the maximun number of commands we could
|
|
170
170
|
* pipeline without kill redis performance.
|
|
171
171
|
*/
|
|
172
|
-
getAll(): Promise<
|
|
173
|
-
return this.redis.keys(this.keys.searchPatternForSplitKeys())
|
|
174
|
-
(listOfKeys) => this.redis.pipeline(listOfKeys.map(k => ['get', k])).exec()
|
|
175
|
-
|
|
172
|
+
getAll(): Promise<ISplit[]> {
|
|
173
|
+
return this.redis.keys(this.keys.searchPatternForSplitKeys())
|
|
174
|
+
.then((listOfKeys) => this.redis.pipeline(listOfKeys.map(k => ['get', k])).exec())
|
|
175
|
+
.then(processPipelineAnswer)
|
|
176
|
+
.then((splitDefinitions) => splitDefinitions.map((splitDefinition) => {
|
|
177
|
+
return JSON.parse(splitDefinition as string);
|
|
178
|
+
}));
|
|
176
179
|
}
|
|
177
180
|
|
|
178
181
|
/**
|
|
@@ -226,19 +229,20 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
226
229
|
* Fetches multiple splits definitions.
|
|
227
230
|
* Returned promise is rejected if redis operation fails.
|
|
228
231
|
*/
|
|
229
|
-
getSplits(names: string[]): Promise<Record<string,
|
|
232
|
+
getSplits(names: string[]): Promise<Record<string, ISplit | null>> {
|
|
230
233
|
if (this.redisError) {
|
|
231
234
|
this.log.error(LOG_PREFIX + this.redisError);
|
|
232
235
|
|
|
233
236
|
return Promise.reject(this.redisError);
|
|
234
237
|
}
|
|
235
238
|
|
|
236
|
-
const splits: Record<string,
|
|
239
|
+
const splits: Record<string, ISplit | null> = {};
|
|
237
240
|
const keys = names.map(name => this.keys.buildSplitKey(name));
|
|
238
241
|
return this.redis.mget(...keys)
|
|
239
242
|
.then(splitDefinitions => {
|
|
240
243
|
names.forEach((name, idx) => {
|
|
241
|
-
|
|
244
|
+
const split = splitDefinitions[idx];
|
|
245
|
+
splits[name] = split && JSON.parse(split);
|
|
242
246
|
});
|
|
243
247
|
return Promise.resolve(splits);
|
|
244
248
|
})
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { ILogger } from '../../logger/types';
|
|
2
|
-
import { Method } from '../../sync/submitters/types';
|
|
3
|
-
import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
2
|
+
import { Method, MultiConfigs, MultiMethodExceptions, MultiMethodLatencies } from '../../sync/submitters/types';
|
|
3
|
+
import { KeyBuilderSS, parseExceptionField, parseLatencyField, parseMetadata } from '../KeyBuilderSS';
|
|
4
4
|
import { ITelemetryCacheAsync } from '../types';
|
|
5
5
|
import { findLatencyIndex } from '../findLatencyIndex';
|
|
6
6
|
import { Redis } from 'ioredis';
|
|
7
7
|
import { getTelemetryConfigStats } from '../../sync/submitters/telemetrySubmitter';
|
|
8
8
|
import { CONSUMER_MODE, STORAGE_REDIS } from '../../utils/constants';
|
|
9
|
+
import { isNaNNumber, isString } from '../../utils/lang';
|
|
10
|
+
import { _Map } from '../../utils/lang/maps';
|
|
11
|
+
import { MAX_LATENCY_BUCKET_COUNT, newBuckets } from '../inMemory/TelemetryCacheInMemory';
|
|
9
12
|
|
|
10
13
|
export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
11
14
|
|
|
@@ -22,6 +25,7 @@ export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
|
22
25
|
return this.redis.hincrby(key, field, 1)
|
|
23
26
|
.catch(() => { /* Handle rejections for telemetry */ });
|
|
24
27
|
}
|
|
28
|
+
|
|
25
29
|
recordException(method: Method) {
|
|
26
30
|
const [key, field] = this.keys.buildExceptionKey(method).split('::');
|
|
27
31
|
return this.redis.hincrby(key, field, 1)
|
|
@@ -33,4 +37,120 @@ export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
|
33
37
|
const value = JSON.stringify(getTelemetryConfigStats(CONSUMER_MODE, STORAGE_REDIS));
|
|
34
38
|
return this.redis.hset(key, field, value).catch(() => { /* Handle rejections for telemetry */ });
|
|
35
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Pop telemetry latencies.
|
|
43
|
+
* The returned promise rejects if redis operations fail.
|
|
44
|
+
*/
|
|
45
|
+
popLatencies(): Promise<MultiMethodLatencies> {
|
|
46
|
+
return this.redis.hgetall(this.keys.latencyPrefix).then(latencies => {
|
|
47
|
+
|
|
48
|
+
const result: MultiMethodLatencies = new _Map();
|
|
49
|
+
|
|
50
|
+
Object.keys(latencies).forEach(field => {
|
|
51
|
+
|
|
52
|
+
const parsedField = parseLatencyField(field);
|
|
53
|
+
if (isString(parsedField)) {
|
|
54
|
+
this.log.error(`Ignoring invalid latency field: ${field}: ${parsedField}`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const count = parseInt(latencies[field]);
|
|
59
|
+
if (isNaNNumber(count)) {
|
|
60
|
+
this.log.error(`Ignoring latency with invalid count: ${latencies[field]}`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const [metadata, method, bucket] = parsedField;
|
|
65
|
+
|
|
66
|
+
if (bucket >= MAX_LATENCY_BUCKET_COUNT) {
|
|
67
|
+
this.log.error(`Ignoring latency with invalid bucket: ${bucket}`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!result.has(metadata)) result.set(metadata, {
|
|
72
|
+
t: newBuckets(),
|
|
73
|
+
ts: newBuckets(),
|
|
74
|
+
tc: newBuckets(),
|
|
75
|
+
tcs: newBuckets(),
|
|
76
|
+
tr: newBuckets(),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
result.get(metadata)![method][bucket] = count;
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return this.redis.del(this.keys.latencyPrefix).then(() => result);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Pop telemetry exceptions.
|
|
88
|
+
* The returned promise rejects if redis operations fail.
|
|
89
|
+
*/
|
|
90
|
+
popExceptions(): Promise<MultiMethodExceptions> {
|
|
91
|
+
return this.redis.hgetall(this.keys.exceptionPrefix).then(exceptions => {
|
|
92
|
+
|
|
93
|
+
const result: MultiMethodExceptions = new _Map();
|
|
94
|
+
|
|
95
|
+
Object.keys(exceptions).forEach(field => {
|
|
96
|
+
|
|
97
|
+
const parsedField = parseExceptionField(field);
|
|
98
|
+
if (isString(parsedField)) {
|
|
99
|
+
this.log.error(`Ignoring invalid exception field: ${field}: ${parsedField}`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const count = parseInt(exceptions[field]);
|
|
104
|
+
if (isNaNNumber(count)) {
|
|
105
|
+
this.log.error(`Ignoring exception with invalid count: ${exceptions[field]}`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const [metadata, method] = parsedField;
|
|
110
|
+
|
|
111
|
+
if (!result.has(metadata)) result.set(metadata, {
|
|
112
|
+
t: 0,
|
|
113
|
+
ts: 0,
|
|
114
|
+
tc: 0,
|
|
115
|
+
tcs: 0,
|
|
116
|
+
tr: 0,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
result.get(metadata)![method] = count;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return this.redis.del(this.keys.exceptionPrefix).then(() => result);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Pop telemetry configs.
|
|
128
|
+
* The returned promise rejects if redis operations fail.
|
|
129
|
+
*/
|
|
130
|
+
popConfigs(): Promise<MultiConfigs> {
|
|
131
|
+
return this.redis.hgetall(this.keys.initPrefix).then(configs => {
|
|
132
|
+
|
|
133
|
+
const result: MultiConfigs = new _Map();
|
|
134
|
+
|
|
135
|
+
Object.keys(configs).forEach(field => {
|
|
136
|
+
|
|
137
|
+
const parsedField = parseMetadata(field);
|
|
138
|
+
if (isString(parsedField)) {
|
|
139
|
+
this.log.error(`Ignoring invalid config field: ${field}: ${parsedField}`);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const [metadata] = parsedField;
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const config = JSON.parse(configs[field]);
|
|
147
|
+
result.set(metadata, config);
|
|
148
|
+
} catch (e) {
|
|
149
|
+
this.log.error(`Ignoring invalid config: ${configs[field]}`);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
return this.redis.del(this.keys.initPrefix).then(() => result);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
36
156
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { IUniqueKeysCacheBase } from '../types';
|
|
2
|
+
import { Redis } from 'ioredis';
|
|
3
|
+
import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
|
|
4
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
5
|
+
import { DEFAULT_CACHE_SIZE, REFRESH_RATE, TTL_REFRESH } from './constants';
|
|
6
|
+
import { LOG_PREFIX } from './constants';
|
|
7
|
+
import { ILogger } from '../../logger/types';
|
|
8
|
+
|
|
9
|
+
export class UniqueKeysCacheInRedis extends UniqueKeysCacheInMemory implements IUniqueKeysCacheBase {
|
|
10
|
+
|
|
11
|
+
private readonly log: ILogger;
|
|
12
|
+
private readonly key: string;
|
|
13
|
+
private readonly redis: Redis;
|
|
14
|
+
private readonly refreshRate: number;
|
|
15
|
+
private intervalId: any;
|
|
16
|
+
|
|
17
|
+
constructor(log: ILogger, key: string, redis: Redis, uniqueKeysQueueSize = DEFAULT_CACHE_SIZE, refreshRate = REFRESH_RATE) {
|
|
18
|
+
super(uniqueKeysQueueSize);
|
|
19
|
+
this.log = log;
|
|
20
|
+
this.key = key;
|
|
21
|
+
this.redis = redis;
|
|
22
|
+
this.refreshRate = refreshRate;
|
|
23
|
+
this.onFullQueue = () => {this.postUniqueKeysInRedis();};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private postUniqueKeysInRedis() {
|
|
27
|
+
const featureNames = Object.keys(this.uniqueKeysTracker);
|
|
28
|
+
if (!featureNames.length) return Promise.resolve(false);
|
|
29
|
+
|
|
30
|
+
const pipeline = this.redis.pipeline();
|
|
31
|
+
for (let i = 0; i < featureNames.length; i++) {
|
|
32
|
+
const featureName = featureNames[i];
|
|
33
|
+
const featureKeys = setToArray(this.uniqueKeysTracker[featureName]);
|
|
34
|
+
const uniqueKeysPayload = {
|
|
35
|
+
f: featureName,
|
|
36
|
+
ks: featureKeys
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
pipeline.rpush(this.key, JSON.stringify(uniqueKeysPayload));
|
|
40
|
+
}
|
|
41
|
+
this.clear();
|
|
42
|
+
return pipeline.exec()
|
|
43
|
+
.then(data => {
|
|
44
|
+
// If this is the creation of the key on Redis, set the expiration for it in 3600 seconds.
|
|
45
|
+
if (data.length && data.length === featureNames.length) {
|
|
46
|
+
return this.redis.expire(this.key, TTL_REFRESH);
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
.catch(err => {
|
|
50
|
+
this.log.error(`${LOG_PREFIX}Error in uniqueKeys pipeline: ${err}.`);
|
|
51
|
+
return false;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
start() {
|
|
57
|
+
this.intervalId = setInterval(this.postUniqueKeysInRedis.bind(this), this.refreshRate);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
stop() {
|
|
61
|
+
clearInterval(this.intervalId);
|
|
62
|
+
return this.postUniqueKeysInRedis();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
@@ -6,8 +6,10 @@ import { SplitsCacheInRedis } from './SplitsCacheInRedis';
|
|
|
6
6
|
import { SegmentsCacheInRedis } from './SegmentsCacheInRedis';
|
|
7
7
|
import { ImpressionsCacheInRedis } from './ImpressionsCacheInRedis';
|
|
8
8
|
import { EventsCacheInRedis } from './EventsCacheInRedis';
|
|
9
|
-
import { STORAGE_REDIS } from '../../utils/constants';
|
|
9
|
+
import { DEBUG, NONE, STORAGE_REDIS } from '../../utils/constants';
|
|
10
10
|
import { TelemetryCacheInRedis } from './TelemetryCacheInRedis';
|
|
11
|
+
import { UniqueKeysCacheInRedis } from './UniqueKeysCacheInRedis';
|
|
12
|
+
import { ImpressionCountsCacheInRedis } from './ImpressionCountsCacheInRedis';
|
|
11
13
|
|
|
12
14
|
export interface InRedisStorageOptions {
|
|
13
15
|
prefix?: string
|
|
@@ -22,15 +24,18 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
|
|
|
22
24
|
|
|
23
25
|
const prefix = validatePrefix(options.prefix);
|
|
24
26
|
|
|
25
|
-
function InRedisStorageFactory({ log, metadata, onReadyCb }: IStorageFactoryParams): IStorageAsync {
|
|
26
|
-
|
|
27
|
+
function InRedisStorageFactory({ log, metadata, onReadyCb, impressionsMode }: IStorageFactoryParams): IStorageAsync {
|
|
27
28
|
const keys = new KeyBuilderSS(prefix, metadata);
|
|
28
29
|
const redisClient = new RedisAdapter(log, options.options || {});
|
|
29
30
|
const telemetry = new TelemetryCacheInRedis(log, keys, redisClient);
|
|
31
|
+
const impressionCountsCache = impressionsMode !== DEBUG ? new ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient) : undefined;
|
|
32
|
+
const uniqueKeysCache = impressionsMode === NONE ? new UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient) : undefined;
|
|
30
33
|
|
|
31
34
|
// subscription to Redis connect event in order to emit SDK_READY event on consumer mode
|
|
32
35
|
redisClient.on('connect', () => {
|
|
33
36
|
onReadyCb();
|
|
37
|
+
if (impressionCountsCache) impressionCountsCache.start();
|
|
38
|
+
if (uniqueKeysCache) uniqueKeysCache.start();
|
|
34
39
|
|
|
35
40
|
// Synchronize config
|
|
36
41
|
telemetry.recordConfig();
|
|
@@ -40,13 +45,18 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
|
|
|
40
45
|
splits: new SplitsCacheInRedis(log, keys, redisClient),
|
|
41
46
|
segments: new SegmentsCacheInRedis(log, keys, redisClient),
|
|
42
47
|
impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
|
|
48
|
+
impressionCounts: impressionCountsCache,
|
|
43
49
|
events: new EventsCacheInRedis(log, keys.buildEventsKey(), redisClient, metadata),
|
|
44
50
|
telemetry,
|
|
51
|
+
uniqueKeys: uniqueKeysCache,
|
|
45
52
|
|
|
46
53
|
// When using REDIS we should:
|
|
47
54
|
// 1- Disconnect from the storage
|
|
48
|
-
destroy() {
|
|
49
|
-
|
|
55
|
+
destroy(): Promise<void>{
|
|
56
|
+
let promises = [];
|
|
57
|
+
if (impressionCountsCache) promises.push(impressionCountsCache.stop());
|
|
58
|
+
if (uniqueKeysCache) promises.push(uniqueKeysCache.stop());
|
|
59
|
+
return Promise.all(promises).then(() => { redisClient.disconnect(); });
|
|
50
60
|
// @TODO check that caches works as expected when redisClient is disconnected
|
|
51
61
|
}
|
|
52
62
|
};
|