@splitsoftware/splitio-commons 2.0.3-rc.0 → 2.1.0-rc.1
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 +5 -2
- package/README.md +2 -2
- package/cjs/evaluator/index.js +0 -2
- package/cjs/evaluator/matchers/large_segment.js +0 -6
- package/cjs/evaluator/matchers/segment.js +0 -6
- package/cjs/listeners/browser.js +6 -4
- package/cjs/listeners/node.js +2 -2
- package/cjs/readiness/readinessManager.js +6 -0
- package/cjs/sdkClient/client.js +13 -13
- package/cjs/sdkClient/sdkClient.js +1 -1
- package/cjs/sdkFactory/index.js +14 -9
- package/cjs/sdkManager/index.js +1 -2
- package/cjs/storages/AbstractSplitsCacheAsync.js +0 -7
- package/cjs/storages/AbstractSplitsCacheSync.js +0 -7
- package/cjs/storages/KeyBuilderCS.js +3 -0
- package/cjs/storages/dataLoader.js +3 -2
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +1 -57
- package/cjs/storages/inLocalStorage/index.js +8 -7
- package/cjs/storages/inLocalStorage/validateCache.js +79 -0
- package/cjs/storages/inMemory/InMemoryStorage.js +3 -3
- package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -4
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +1 -1
- package/cjs/storages/inRedis/index.js +13 -9
- package/cjs/storages/pluggable/index.js +21 -16
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -10
- package/cjs/sync/streaming/pushManager.js +8 -6
- package/cjs/sync/submitters/impressionCountsSubmitter.js +4 -2
- package/cjs/sync/submitters/submitterManager.js +6 -3
- package/cjs/sync/syncManagerOnline.js +10 -4
- package/cjs/trackers/eventTracker.js +1 -1
- package/cjs/trackers/impressionsTracker.js +19 -18
- package/cjs/trackers/strategy/strategyDebug.js +11 -4
- package/cjs/trackers/strategy/strategyNone.js +16 -11
- package/cjs/trackers/strategy/strategyOptimized.js +21 -11
- package/cjs/utils/settingsValidation/index.js +1 -1
- package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
- package/esm/evaluator/index.js +0 -2
- package/esm/evaluator/matchers/large_segment.js +0 -6
- package/esm/evaluator/matchers/segment.js +0 -6
- package/esm/listeners/browser.js +3 -1
- package/esm/listeners/node.js +2 -2
- package/esm/readiness/readinessManager.js +6 -0
- package/esm/sdkClient/client.js +13 -13
- package/esm/sdkClient/sdkClient.js +1 -1
- package/esm/sdkFactory/index.js +15 -10
- package/esm/sdkManager/index.js +1 -2
- package/esm/storages/AbstractSplitsCacheAsync.js +0 -7
- package/esm/storages/AbstractSplitsCacheSync.js +0 -7
- package/esm/storages/KeyBuilderCS.js +3 -0
- package/esm/storages/dataLoader.js +2 -1
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +1 -57
- package/esm/storages/inLocalStorage/index.js +9 -8
- package/esm/storages/inLocalStorage/validateCache.js +75 -0
- package/esm/storages/inMemory/InMemoryStorage.js +4 -4
- package/esm/storages/inMemory/InMemoryStorageCS.js +4 -5
- package/esm/storages/inRedis/SplitsCacheInRedis.js +1 -1
- package/esm/storages/inRedis/index.js +14 -10
- package/esm/storages/pluggable/index.js +22 -17
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +3 -2
- package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -11
- package/esm/sync/streaming/pushManager.js +8 -6
- package/esm/sync/submitters/impressionCountsSubmitter.js +4 -2
- package/esm/sync/submitters/submitterManager.js +6 -3
- package/esm/sync/syncManagerOnline.js +10 -4
- package/esm/trackers/eventTracker.js +1 -1
- package/esm/trackers/impressionsTracker.js +19 -18
- package/esm/trackers/strategy/strategyDebug.js +11 -4
- package/esm/trackers/strategy/strategyNone.js +16 -11
- package/esm/trackers/strategy/strategyOptimized.js +21 -11
- package/esm/utils/settingsValidation/index.js +1 -1
- package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
- package/package.json +1 -1
- package/src/dtos/types.ts +1 -2
- package/src/evaluator/index.ts +0 -2
- package/src/evaluator/matchers/large_segment.ts +0 -7
- package/src/evaluator/matchers/segment.ts +0 -7
- package/src/evaluator/types.ts +1 -1
- package/src/listeners/browser.ts +3 -1
- package/src/listeners/node.ts +2 -2
- package/src/readiness/readinessManager.ts +5 -0
- package/src/sdkClient/client.ts +11 -11
- package/src/sdkClient/sdkClient.ts +1 -1
- package/src/sdkFactory/index.ts +16 -11
- package/src/sdkFactory/types.ts +1 -1
- package/src/sdkManager/index.ts +1 -2
- package/src/storages/AbstractSplitsCacheAsync.ts +0 -8
- package/src/storages/AbstractSplitsCacheSync.ts +0 -8
- package/src/storages/KeyBuilderCS.ts +4 -0
- package/src/storages/dataLoader.ts +3 -1
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +1 -66
- package/src/storages/inLocalStorage/index.ts +12 -13
- package/src/storages/inLocalStorage/validateCache.ts +91 -0
- package/src/storages/inMemory/InMemoryStorage.ts +4 -4
- package/src/storages/inMemory/InMemoryStorageCS.ts +4 -5
- package/src/storages/inRedis/SplitsCacheInRedis.ts +1 -1
- package/src/storages/inRedis/index.ts +10 -10
- package/src/storages/pluggable/index.ts +22 -17
- package/src/storages/types.ts +3 -6
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +6 -5
- package/src/sync/polling/updaters/splitChangesUpdater.ts +2 -11
- package/src/sync/streaming/pushManager.ts +8 -6
- package/src/sync/submitters/impressionCountsSubmitter.ts +4 -2
- package/src/sync/submitters/submitterManager.ts +4 -3
- package/src/sync/submitters/uniqueKeysSubmitter.ts +3 -2
- package/src/sync/syncManagerOnline.ts +11 -5
- package/src/trackers/eventTracker.ts +1 -1
- package/src/trackers/impressionsTracker.ts +19 -18
- package/src/trackers/strategy/strategyDebug.ts +11 -4
- package/src/trackers/strategy/strategyNone.ts +17 -11
- package/src/trackers/strategy/strategyOptimized.ts +20 -10
- package/src/trackers/types.ts +8 -2
- package/src/utils/lang/index.ts +1 -1
- package/src/utils/settingsValidation/index.ts +1 -1
- package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
- package/types/index.d.ts +1 -1
- package/types/splitio.d.ts +26 -6
- package/cjs/utils/constants/browser.js +0 -5
- package/esm/utils/constants/browser.js +0 -2
- package/src/utils/constants/browser.ts +0 -2
package/src/sdkFactory/index.ts
CHANGED
|
@@ -13,7 +13,7 @@ import { strategyDebugFactory } from '../trackers/strategy/strategyDebug';
|
|
|
13
13
|
import { strategyOptimizedFactory } from '../trackers/strategy/strategyOptimized';
|
|
14
14
|
import { strategyNoneFactory } from '../trackers/strategy/strategyNone';
|
|
15
15
|
import { uniqueKeysTrackerFactory } from '../trackers/uniqueKeysTracker';
|
|
16
|
-
import {
|
|
16
|
+
import { NONE, OPTIMIZED } from '../utils/constants';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Modular SDK factory
|
|
@@ -59,16 +59,21 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IA
|
|
|
59
59
|
const integrationsManager = integrationsManagerFactory && integrationsManagerFactory({ settings, storage, telemetryTracker });
|
|
60
60
|
|
|
61
61
|
const observer = impressionsObserverFactory();
|
|
62
|
-
const uniqueKeysTracker = uniqueKeysTrackerFactory(log, storage.uniqueKeys
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
const uniqueKeysTracker = impressionsMode === NONE ? uniqueKeysTrackerFactory(log, storage.uniqueKeys!, filterAdapterFactory && filterAdapterFactory()) : undefined;
|
|
63
|
+
|
|
64
|
+
let strategy;
|
|
65
|
+
switch (impressionsMode) {
|
|
66
|
+
case OPTIMIZED:
|
|
67
|
+
strategy = strategyOptimizedFactory(observer, storage.impressionCounts!);
|
|
68
|
+
break;
|
|
69
|
+
case NONE:
|
|
70
|
+
strategy = strategyNoneFactory(storage.impressionCounts!, uniqueKeysTracker!);
|
|
71
|
+
break;
|
|
72
|
+
default:
|
|
73
|
+
strategy = strategyDebugFactory(observer);
|
|
74
|
+
}
|
|
70
75
|
|
|
71
|
-
const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions,
|
|
76
|
+
const impressionsTracker = impressionsTrackerFactory(settings, storage.impressions, strategy, whenInit, integrationsManager, storage.telemetry);
|
|
72
77
|
const eventTracker = eventTrackerFactory(settings, storage.events, whenInit, integrationsManager, storage.telemetry);
|
|
73
78
|
|
|
74
79
|
// splitApi is used by SyncManager and Browser signal listener
|
|
@@ -94,7 +99,7 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ISDK | SplitIO.IA
|
|
|
94
99
|
// We will just log and allow for the SDK to end up throwing an SDK_TIMEOUT event for devs to handle.
|
|
95
100
|
validateAndTrackApiKey(log, settings.core.authorizationKey);
|
|
96
101
|
readiness.init();
|
|
97
|
-
uniqueKeysTracker.start();
|
|
102
|
+
uniqueKeysTracker && uniqueKeysTracker.start();
|
|
98
103
|
syncManager && syncManager.start();
|
|
99
104
|
signalListener && signalListener.start();
|
|
100
105
|
|
package/src/sdkFactory/types.ts
CHANGED
|
@@ -46,7 +46,7 @@ export interface ISdkFactoryContext {
|
|
|
46
46
|
eventTracker: IEventTracker,
|
|
47
47
|
telemetryTracker: ITelemetryTracker,
|
|
48
48
|
storage: IStorageSync | IStorageAsync,
|
|
49
|
-
uniqueKeysTracker
|
|
49
|
+
uniqueKeysTracker?: IUniqueKeysTracker,
|
|
50
50
|
signalListener?: ISignalListener
|
|
51
51
|
splitApi?: ISplitApi
|
|
52
52
|
syncManager?: ISyncManager,
|
package/src/sdkManager/index.ts
CHANGED
|
@@ -31,8 +31,7 @@ function objectToView(splitObject: ISplit | null): SplitIO.SplitView | null {
|
|
|
31
31
|
treatments: collectTreatments(splitObject),
|
|
32
32
|
configs: splitObject.configurations || {},
|
|
33
33
|
sets: splitObject.sets || [],
|
|
34
|
-
defaultTreatment: splitObject.defaultTreatment
|
|
35
|
-
trackImpressions: splitObject.trackImpressions !== false
|
|
34
|
+
defaultTreatment: splitObject.defaultTreatment
|
|
36
35
|
};
|
|
37
36
|
}
|
|
38
37
|
|
|
@@ -27,14 +27,6 @@ export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
|
|
|
27
27
|
return Promise.resolve(true);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
/**
|
|
31
|
-
* Check if the splits information is already stored in cache.
|
|
32
|
-
* Noop, just keeping the interface. This is used by client-side implementations only.
|
|
33
|
-
*/
|
|
34
|
-
checkCache(): Promise<boolean> {
|
|
35
|
-
return Promise.resolve(false);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
30
|
/**
|
|
39
31
|
* Kill `name` split and set `defaultTreatment` and `changeNumber`.
|
|
40
32
|
* Used for SPLIT_KILL push notifications.
|
|
@@ -47,14 +47,6 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
|
|
|
47
47
|
|
|
48
48
|
abstract clear(): void
|
|
49
49
|
|
|
50
|
-
/**
|
|
51
|
-
* Check if the splits information is already stored in cache. This data can be preloaded.
|
|
52
|
-
* It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE.
|
|
53
|
-
*/
|
|
54
|
-
checkCache(): boolean {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
50
|
/**
|
|
59
51
|
* Kill `name` split and set `defaultTreatment` and `changeNumber`.
|
|
60
52
|
* Used for SPLIT_KILL push notifications.
|
|
@@ -43,6 +43,10 @@ export class KeyBuilderCS extends KeyBuilder implements MySegmentsKeyBuilder {
|
|
|
43
43
|
buildTillKey() {
|
|
44
44
|
return `${this.prefix}.${this.matchingKey}.segments.till`;
|
|
45
45
|
}
|
|
46
|
+
|
|
47
|
+
buildLastClear() {
|
|
48
|
+
return `${this.prefix}.lastClear`;
|
|
49
|
+
}
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
export function myLargeSegmentsKeyBuilder(prefix: string, matchingKey: string): MySegmentsKeyBuilder {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { PreloadedData } from '../types';
|
|
2
|
-
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../utils/constants/browser';
|
|
3
2
|
import { DataLoader, ISegmentsCacheSync, ISplitsCacheSync } from './types';
|
|
4
3
|
|
|
4
|
+
// This value might be eventually set via a config parameter
|
|
5
|
+
const DEFAULT_CACHE_EXPIRATION_IN_MILLIS = 864000000; // 10 days
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* Factory of client-side storage loader
|
|
7
9
|
*
|
|
@@ -5,7 +5,6 @@ import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
|
5
5
|
import { ILogger } from '../../logger/types';
|
|
6
6
|
import { LOG_PREFIX } from './constants';
|
|
7
7
|
import { ISettings } from '../../types';
|
|
8
|
-
import { getStorageHash } from '../KeyBuilder';
|
|
9
8
|
import { setToArray } from '../../utils/lang/sets';
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -15,21 +14,14 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
15
14
|
|
|
16
15
|
private readonly keys: KeyBuilderCS;
|
|
17
16
|
private readonly log: ILogger;
|
|
18
|
-
private readonly storageHash: string;
|
|
19
17
|
private readonly flagSetsFilter: string[];
|
|
20
18
|
private hasSync?: boolean;
|
|
21
|
-
private updateNewFilter?: boolean;
|
|
22
19
|
|
|
23
|
-
constructor(settings: ISettings, keys: KeyBuilderCS
|
|
20
|
+
constructor(settings: ISettings, keys: KeyBuilderCS) {
|
|
24
21
|
super();
|
|
25
22
|
this.keys = keys;
|
|
26
23
|
this.log = settings.log;
|
|
27
|
-
this.storageHash = getStorageHash(settings);
|
|
28
24
|
this.flagSetsFilter = settings.sync.__splitFiltersValidation.groupedFilters.bySet;
|
|
29
|
-
|
|
30
|
-
this._checkExpiration(expirationTimestamp);
|
|
31
|
-
|
|
32
|
-
this._checkFilterQuery();
|
|
33
25
|
}
|
|
34
26
|
|
|
35
27
|
private _decrementCount(key: string) {
|
|
@@ -79,8 +71,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
79
71
|
* We cannot simply call `localStorage.clear()` since that implies removing user items from the storage.
|
|
80
72
|
*/
|
|
81
73
|
clear() {
|
|
82
|
-
this.log.info(LOG_PREFIX + 'Flushing Splits data from localStorage');
|
|
83
|
-
|
|
84
74
|
// collect item keys
|
|
85
75
|
const len = localStorage.length;
|
|
86
76
|
const accum = [];
|
|
@@ -138,19 +128,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
138
128
|
}
|
|
139
129
|
|
|
140
130
|
setChangeNumber(changeNumber: number): boolean {
|
|
141
|
-
|
|
142
|
-
// when using a new split query, we must update it at the store
|
|
143
|
-
if (this.updateNewFilter) {
|
|
144
|
-
this.log.info(LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version was modified. Updating cache');
|
|
145
|
-
const storageHashKey = this.keys.buildHashKey();
|
|
146
|
-
try {
|
|
147
|
-
localStorage.setItem(storageHashKey, this.storageHash);
|
|
148
|
-
} catch (e) {
|
|
149
|
-
this.log.error(LOG_PREFIX + e);
|
|
150
|
-
}
|
|
151
|
-
this.updateNewFilter = false;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
131
|
try {
|
|
155
132
|
localStorage.setItem(this.keys.buildSplitsTillKey(), changeNumber + '');
|
|
156
133
|
// update "last updated" timestamp with current time
|
|
@@ -212,48 +189,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
212
189
|
}
|
|
213
190
|
}
|
|
214
191
|
|
|
215
|
-
/**
|
|
216
|
-
* Check if the splits information is already stored in browser LocalStorage.
|
|
217
|
-
* In this function we could add more code to check if the data is valid.
|
|
218
|
-
* @override
|
|
219
|
-
*/
|
|
220
|
-
checkCache(): boolean {
|
|
221
|
-
return this.getChangeNumber() > -1;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
|
|
226
|
-
*
|
|
227
|
-
* @param expirationTimestamp - if the value is not a number, data will not be cleaned
|
|
228
|
-
*/
|
|
229
|
-
private _checkExpiration(expirationTimestamp?: number) {
|
|
230
|
-
let value: string | number | null = localStorage.getItem(this.keys.buildLastUpdatedKey());
|
|
231
|
-
if (value !== null) {
|
|
232
|
-
value = parseInt(value, 10);
|
|
233
|
-
if (!isNaNNumber(value) && expirationTimestamp && value < expirationTimestamp) this.clear();
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// @TODO eventually remove `_checkFilterQuery`. Cache should be cleared at the storage level, reusing same logic than PluggableStorage
|
|
238
|
-
private _checkFilterQuery() {
|
|
239
|
-
const storageHashKey = this.keys.buildHashKey();
|
|
240
|
-
const storageHash = localStorage.getItem(storageHashKey);
|
|
241
|
-
|
|
242
|
-
if (storageHash !== this.storageHash) {
|
|
243
|
-
try {
|
|
244
|
-
// mark cache to update the new query filter on first successful splits fetch
|
|
245
|
-
this.updateNewFilter = true;
|
|
246
|
-
|
|
247
|
-
// if there is cache, clear it
|
|
248
|
-
if (this.checkCache()) this.clear();
|
|
249
|
-
|
|
250
|
-
} catch (e) {
|
|
251
|
-
this.log.error(LOG_PREFIX + e);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
// if the filter didn't change, nothing is done
|
|
255
|
-
}
|
|
256
|
-
|
|
257
192
|
getNamesByFlagSets(flagSets: string[]): Set<string>[] {
|
|
258
193
|
return flagSets.map(flagSet => {
|
|
259
194
|
const flagSetKey = this.keys.buildFlagSetKey(flagSet);
|
|
@@ -7,22 +7,19 @@ import { KeyBuilderCS, myLargeSegmentsKeyBuilder } from '../KeyBuilderCS';
|
|
|
7
7
|
import { isLocalStorageAvailable } from '../../utils/env/isLocalStorageAvailable';
|
|
8
8
|
import { SplitsCacheInLocal } from './SplitsCacheInLocal';
|
|
9
9
|
import { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
|
|
10
|
-
import { DEFAULT_CACHE_EXPIRATION_IN_MILLIS } from '../../utils/constants/browser';
|
|
11
10
|
import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS';
|
|
12
11
|
import { LOG_PREFIX } from './constants';
|
|
13
|
-
import { STORAGE_LOCALSTORAGE } from '../../utils/constants';
|
|
12
|
+
import { DEBUG, NONE, STORAGE_LOCALSTORAGE } from '../../utils/constants';
|
|
14
13
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from '../inMemory/TelemetryCacheInMemory';
|
|
15
14
|
import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
|
|
16
15
|
import { getMatching } from '../../utils/key';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
prefix?: string
|
|
20
|
-
}
|
|
16
|
+
import { validateCache } from './validateCache';
|
|
17
|
+
import SplitIO from '../../../types/splitio';
|
|
21
18
|
|
|
22
19
|
/**
|
|
23
20
|
* InLocal storage factory for standalone client-side SplitFactory
|
|
24
21
|
*/
|
|
25
|
-
export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyncFactory {
|
|
22
|
+
export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): IStorageSyncFactory {
|
|
26
23
|
|
|
27
24
|
const prefix = validatePrefix(options.prefix);
|
|
28
25
|
|
|
@@ -34,12 +31,11 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
34
31
|
return InMemoryStorageCSFactory(params);
|
|
35
32
|
}
|
|
36
33
|
|
|
37
|
-
const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize } } } = params;
|
|
34
|
+
const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode } } } = params;
|
|
38
35
|
const matchingKey = getMatching(settings.core.key);
|
|
39
36
|
const keys = new KeyBuilderCS(prefix, matchingKey);
|
|
40
|
-
const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
|
|
41
37
|
|
|
42
|
-
const splits = new SplitsCacheInLocal(settings, keys
|
|
38
|
+
const splits = new SplitsCacheInLocal(settings, keys);
|
|
43
39
|
const segments = new MySegmentsCacheInLocal(log, keys);
|
|
44
40
|
const largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey));
|
|
45
41
|
|
|
@@ -48,10 +44,14 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
48
44
|
segments,
|
|
49
45
|
largeSegments,
|
|
50
46
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
51
|
-
impressionCounts: new ImpressionCountsCacheInMemory(),
|
|
47
|
+
impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
|
|
52
48
|
events: new EventsCacheInMemory(eventsQueueSize),
|
|
53
49
|
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
|
|
54
|
-
uniqueKeys: new UniqueKeysCacheInMemoryCS(),
|
|
50
|
+
uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
|
|
51
|
+
|
|
52
|
+
validateCache() {
|
|
53
|
+
return validateCache(options, settings, keys, splits, segments, largeSegments);
|
|
54
|
+
},
|
|
55
55
|
|
|
56
56
|
destroy() { },
|
|
57
57
|
|
|
@@ -66,7 +66,6 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
|
|
|
66
66
|
impressionCounts: this.impressionCounts,
|
|
67
67
|
events: this.events,
|
|
68
68
|
telemetry: this.telemetry,
|
|
69
|
-
uniqueKeys: this.uniqueKeys,
|
|
70
69
|
|
|
71
70
|
destroy() { }
|
|
72
71
|
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ISettings } from '../../types';
|
|
2
|
+
import { isFiniteNumber, isNaNNumber } from '../../utils/lang';
|
|
3
|
+
import { getStorageHash } from '../KeyBuilder';
|
|
4
|
+
import { LOG_PREFIX } from './constants';
|
|
5
|
+
import type { SplitsCacheInLocal } from './SplitsCacheInLocal';
|
|
6
|
+
import type { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
|
|
7
|
+
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
8
|
+
import SplitIO from '../../../types/splitio';
|
|
9
|
+
|
|
10
|
+
const DEFAULT_CACHE_EXPIRATION_IN_DAYS = 10;
|
|
11
|
+
const MILLIS_IN_A_DAY = 86400000;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Validates if cache should be cleared and sets the cache `hash` if needed.
|
|
15
|
+
*
|
|
16
|
+
* @returns `true` if cache should be cleared, `false` otherwise
|
|
17
|
+
*/
|
|
18
|
+
function validateExpiration(options: SplitIO.InLocalStorageOptions, settings: ISettings, keys: KeyBuilderCS, currentTimestamp: number, isThereCache: boolean) {
|
|
19
|
+
const { log } = settings;
|
|
20
|
+
|
|
21
|
+
// Check expiration
|
|
22
|
+
const lastUpdatedTimestamp = parseInt(localStorage.getItem(keys.buildLastUpdatedKey()) as string, 10);
|
|
23
|
+
if (!isNaNNumber(lastUpdatedTimestamp)) {
|
|
24
|
+
const cacheExpirationInDays = isFiniteNumber(options.expirationDays) && options.expirationDays >= 1 ? options.expirationDays : DEFAULT_CACHE_EXPIRATION_IN_DAYS;
|
|
25
|
+
const expirationTimestamp = currentTimestamp - MILLIS_IN_A_DAY * cacheExpirationInDays;
|
|
26
|
+
if (lastUpdatedTimestamp < expirationTimestamp) {
|
|
27
|
+
log.info(LOG_PREFIX + 'Cache expired more than ' + cacheExpirationInDays + ' days ago. Cleaning up cache');
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Check hash
|
|
33
|
+
const storageHashKey = keys.buildHashKey();
|
|
34
|
+
const storageHash = localStorage.getItem(storageHashKey);
|
|
35
|
+
const currentStorageHash = getStorageHash(settings);
|
|
36
|
+
|
|
37
|
+
if (storageHash !== currentStorageHash) {
|
|
38
|
+
try {
|
|
39
|
+
localStorage.setItem(storageHashKey, currentStorageHash);
|
|
40
|
+
} catch (e) {
|
|
41
|
+
log.error(LOG_PREFIX + e);
|
|
42
|
+
}
|
|
43
|
+
if (isThereCache) {
|
|
44
|
+
log.info(LOG_PREFIX + 'SDK key, flags filter criteria, or flags spec version has changed. Cleaning up cache');
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
return false; // No cache to clear
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Clear on init
|
|
51
|
+
if (options.clearOnInit) {
|
|
52
|
+
const lastClearTimestamp = parseInt(localStorage.getItem(keys.buildLastClear()) as string, 10);
|
|
53
|
+
|
|
54
|
+
if (isNaNNumber(lastClearTimestamp) || lastClearTimestamp < currentTimestamp - MILLIS_IN_A_DAY) {
|
|
55
|
+
log.info(LOG_PREFIX + 'clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache');
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Clean cache if:
|
|
63
|
+
* - it has expired, i.e., its `lastUpdated` timestamp is older than the given `expirationTimestamp`
|
|
64
|
+
* - its hash has changed, i.e., the SDK key, flags filter criteria or flags spec version was modified
|
|
65
|
+
* - `clearOnInit` was set and cache was not cleared in the last 24 hours
|
|
66
|
+
*
|
|
67
|
+
* @returns `true` if cache is ready to be used, `false` otherwise (cache was cleared or there is no cache)
|
|
68
|
+
*/
|
|
69
|
+
export function validateCache(options: SplitIO.InLocalStorageOptions, settings: ISettings, keys: KeyBuilderCS, splits: SplitsCacheInLocal, segments: MySegmentsCacheInLocal, largeSegments: MySegmentsCacheInLocal): boolean {
|
|
70
|
+
|
|
71
|
+
const currentTimestamp = Date.now();
|
|
72
|
+
const isThereCache = splits.getChangeNumber() > -1;
|
|
73
|
+
|
|
74
|
+
if (validateExpiration(options, settings, keys, currentTimestamp, isThereCache)) {
|
|
75
|
+
splits.clear();
|
|
76
|
+
segments.clear();
|
|
77
|
+
largeSegments.clear();
|
|
78
|
+
|
|
79
|
+
// Update last clear timestamp
|
|
80
|
+
try {
|
|
81
|
+
localStorage.setItem(keys.buildLastClear(), currentTimestamp + '');
|
|
82
|
+
} catch (e) {
|
|
83
|
+
settings.log.error(LOG_PREFIX + e);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Check if ready from cache
|
|
90
|
+
return isThereCache;
|
|
91
|
+
}
|
|
@@ -4,7 +4,7 @@ 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 { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
|
|
7
|
+
import { DEBUG, LOCALHOST_MODE, NONE, STORAGE_MEMORY } from '../../utils/constants';
|
|
8
8
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
9
9
|
import { UniqueKeysCacheInMemory } from './UniqueKeysCacheInMemory';
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ import { UniqueKeysCacheInMemory } from './UniqueKeysCacheInMemory';
|
|
|
14
14
|
* @param params - parameters required by EventsCacheSync
|
|
15
15
|
*/
|
|
16
16
|
export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageSync {
|
|
17
|
-
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { __splitFiltersValidation } } } = params;
|
|
17
|
+
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation } } } = params;
|
|
18
18
|
|
|
19
19
|
const splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
20
20
|
const segments = new SegmentsCacheInMemory();
|
|
@@ -23,10 +23,10 @@ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageS
|
|
|
23
23
|
splits,
|
|
24
24
|
segments,
|
|
25
25
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
26
|
-
impressionCounts: new ImpressionCountsCacheInMemory(),
|
|
26
|
+
impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
|
|
27
27
|
events: new EventsCacheInMemory(eventsQueueSize),
|
|
28
28
|
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
|
|
29
|
-
uniqueKeys: new UniqueKeysCacheInMemory(),
|
|
29
|
+
uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemory() : undefined,
|
|
30
30
|
|
|
31
31
|
destroy() { }
|
|
32
32
|
};
|
|
@@ -4,7 +4,7 @@ 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 { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
|
|
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
10
|
|
|
@@ -14,7 +14,7 @@ import { UniqueKeysCacheInMemoryCS } from './UniqueKeysCacheInMemoryCS';
|
|
|
14
14
|
* @param params - parameters required by EventsCacheSync
|
|
15
15
|
*/
|
|
16
16
|
export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorageSync {
|
|
17
|
-
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize }, sync: { __splitFiltersValidation } } } = params;
|
|
17
|
+
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation } } } = params;
|
|
18
18
|
|
|
19
19
|
const splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
20
20
|
const segments = new MySegmentsCacheInMemory();
|
|
@@ -25,10 +25,10 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
25
25
|
segments,
|
|
26
26
|
largeSegments,
|
|
27
27
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
28
|
-
impressionCounts: new ImpressionCountsCacheInMemory(),
|
|
28
|
+
impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
|
|
29
29
|
events: new EventsCacheInMemory(eventsQueueSize),
|
|
30
30
|
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
|
|
31
|
-
uniqueKeys: new UniqueKeysCacheInMemoryCS(),
|
|
31
|
+
uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
|
|
32
32
|
|
|
33
33
|
destroy() { },
|
|
34
34
|
|
|
@@ -42,7 +42,6 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
42
42
|
impressionCounts: this.impressionCounts,
|
|
43
43
|
events: this.events,
|
|
44
44
|
telemetry: this.telemetry,
|
|
45
|
-
uniqueKeys: this.uniqueKeys,
|
|
46
45
|
|
|
47
46
|
destroy() { }
|
|
48
47
|
};
|
|
@@ -266,10 +266,10 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
|
|
|
266
266
|
return Promise.reject(this.redisError);
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
-
const splits: Record<string, ISplit | null> = {};
|
|
270
269
|
const keys = names.map(name => this.keys.buildSplitKey(name));
|
|
271
270
|
return this.redis.mget(...keys)
|
|
272
271
|
.then(splitDefinitions => {
|
|
272
|
+
const splits: Record<string, ISplit | null> = {};
|
|
273
273
|
names.forEach((name, idx) => {
|
|
274
274
|
const split = splitDefinitions[idx];
|
|
275
275
|
splits[name] = split && JSON.parse(split);
|
|
@@ -6,7 +6,7 @@ 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
11
|
import { UniqueKeysCacheInRedis } from './UniqueKeysCacheInRedis';
|
|
12
12
|
import { ImpressionCountsCacheInRedis } from './ImpressionCountsCacheInRedis';
|
|
@@ -30,19 +30,19 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
|
|
|
30
30
|
const prefix = validatePrefix(options.prefix);
|
|
31
31
|
|
|
32
32
|
function InRedisStorageFactory(params: IStorageFactoryParams): IStorageAsync {
|
|
33
|
-
const { onReadyCb, settings, settings: { log } } = params;
|
|
33
|
+
const { onReadyCb, settings, settings: { log, sync: { impressionsMode } } } = params;
|
|
34
34
|
const metadata = metadataBuilder(settings);
|
|
35
35
|
const keys = new KeyBuilderSS(prefix, metadata);
|
|
36
36
|
const redisClient: RedisAdapter = new RD(log, options.options || {});
|
|
37
37
|
const telemetry = new TelemetryCacheInRedis(log, keys, redisClient);
|
|
38
|
-
const impressionCountsCache = new ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient);
|
|
39
|
-
const uniqueKeysCache = new UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient);
|
|
38
|
+
const impressionCountsCache = impressionsMode !== DEBUG ? new ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient) : undefined;
|
|
39
|
+
const uniqueKeysCache = impressionsMode === NONE ? new UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient) : undefined;
|
|
40
40
|
|
|
41
41
|
// subscription to Redis connect event in order to emit SDK_READY event on consumer mode
|
|
42
42
|
redisClient.on('connect', () => {
|
|
43
43
|
onReadyCb();
|
|
44
|
-
impressionCountsCache.start();
|
|
45
|
-
uniqueKeysCache.start();
|
|
44
|
+
if (impressionCountsCache) impressionCountsCache.start();
|
|
45
|
+
if (uniqueKeysCache) uniqueKeysCache.start();
|
|
46
46
|
|
|
47
47
|
// Synchronize config
|
|
48
48
|
telemetry.recordConfig();
|
|
@@ -60,10 +60,10 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
|
|
|
60
60
|
// When using REDIS we should:
|
|
61
61
|
// 1- Disconnect from the storage
|
|
62
62
|
destroy(): Promise<void> {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
let promises = [];
|
|
64
|
+
if (impressionCountsCache) promises.push(impressionCountsCache.stop());
|
|
65
|
+
if (uniqueKeysCache) promises.push(uniqueKeysCache.stop());
|
|
66
|
+
return Promise.all(promises).then(() => { redisClient.disconnect(); });
|
|
67
67
|
// @TODO check that caches works as expected when redisClient is disconnected
|
|
68
68
|
}
|
|
69
69
|
};
|
|
@@ -8,7 +8,7 @@ import { EventsCachePluggable } from './EventsCachePluggable';
|
|
|
8
8
|
import { wrapperAdapter, METHODS_TO_PROMISE_WRAP } from './wrapperAdapter';
|
|
9
9
|
import { isObject } from '../../utils/lang';
|
|
10
10
|
import { getStorageHash, validatePrefix } from '../KeyBuilder';
|
|
11
|
-
import { CONSUMER_PARTIAL_MODE, STORAGE_PLUGGABLE } from '../../utils/constants';
|
|
11
|
+
import { CONSUMER_PARTIAL_MODE, DEBUG, NONE, STORAGE_PLUGGABLE } from '../../utils/constants';
|
|
12
12
|
import { ImpressionsCacheInMemory } from '../inMemory/ImpressionsCacheInMemory';
|
|
13
13
|
import { EventsCacheInMemory } from '../inMemory/EventsCacheInMemory';
|
|
14
14
|
import { ImpressionCountsCacheInMemory } from '../inMemory/ImpressionCountsCacheInMemory';
|
|
@@ -63,32 +63,37 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
63
63
|
const prefix = validatePrefix(options.prefix);
|
|
64
64
|
|
|
65
65
|
function PluggableStorageFactory(params: IStorageFactoryParams): IStorageAsync {
|
|
66
|
-
const { onReadyCb, settings, settings: { log, mode, scheduler: { impressionsQueueSize, eventsQueueSize } } } = params;
|
|
66
|
+
const { onReadyCb, settings, settings: { log, mode, sync: { impressionsMode }, scheduler: { impressionsQueueSize, eventsQueueSize } } } = params;
|
|
67
67
|
const metadata = metadataBuilder(settings);
|
|
68
68
|
const keys = new KeyBuilderSS(prefix, metadata);
|
|
69
69
|
const wrapper = wrapperAdapter(log, options.wrapper);
|
|
70
70
|
|
|
71
|
-
const
|
|
71
|
+
const isSyncronizer = mode === undefined; // If mode is not defined, the synchronizer is running
|
|
72
72
|
const isPartialConsumer = mode === CONSUMER_PARTIAL_MODE;
|
|
73
73
|
|
|
74
|
-
const telemetry = shouldRecordTelemetry(params) ||
|
|
74
|
+
const telemetry = shouldRecordTelemetry(params) || isSyncronizer ?
|
|
75
75
|
isPartialConsumer ?
|
|
76
76
|
new TelemetryCacheInMemory() :
|
|
77
77
|
new TelemetryCachePluggable(log, keys, wrapper) :
|
|
78
78
|
undefined;
|
|
79
79
|
|
|
80
|
-
const impressionCountsCache =
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
const impressionCountsCache = impressionsMode !== DEBUG || isSyncronizer ?
|
|
81
|
+
isPartialConsumer ?
|
|
82
|
+
new ImpressionCountsCacheInMemory() :
|
|
83
|
+
new ImpressionCountsCachePluggable(log, keys.buildImpressionsCountKey(), wrapper) :
|
|
84
|
+
undefined;
|
|
83
85
|
|
|
84
|
-
const uniqueKeysCache =
|
|
85
|
-
|
|
86
|
-
|
|
86
|
+
const uniqueKeysCache = impressionsMode === NONE || isSyncronizer ?
|
|
87
|
+
isPartialConsumer ?
|
|
88
|
+
settings.core.key === undefined ? new UniqueKeysCacheInMemory() : new UniqueKeysCacheInMemoryCS() :
|
|
89
|
+
new UniqueKeysCachePluggable(log, keys.buildUniqueKeysKey(), wrapper) :
|
|
90
|
+
undefined;
|
|
87
91
|
|
|
88
92
|
// Connects to wrapper and emits SDK_READY event on main client
|
|
89
93
|
const connectPromise = wrapper.connect().then(() => {
|
|
90
|
-
if (
|
|
91
|
-
//
|
|
94
|
+
if (isSyncronizer) {
|
|
95
|
+
// @TODO reuse InLocalStorage::validateCache logic
|
|
96
|
+
// In standalone or producer mode, clear storage if SDK key, flags filter criteria or flags spec version was modified
|
|
92
97
|
return wrapper.get(keys.buildHashKey()).then((hash) => {
|
|
93
98
|
const currentHash = getStorageHash(settings);
|
|
94
99
|
if (hash !== currentHash) {
|
|
@@ -102,8 +107,8 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
102
107
|
});
|
|
103
108
|
} else {
|
|
104
109
|
// Start periodic flush of async storages if not running synchronizer (producer mode)
|
|
105
|
-
if ((impressionCountsCache as ImpressionCountsCachePluggable).start) (impressionCountsCache as ImpressionCountsCachePluggable).start();
|
|
106
|
-
if ((uniqueKeysCache as UniqueKeysCachePluggable).start) (uniqueKeysCache as UniqueKeysCachePluggable).start();
|
|
110
|
+
if (impressionCountsCache && (impressionCountsCache as ImpressionCountsCachePluggable).start) (impressionCountsCache as ImpressionCountsCachePluggable).start();
|
|
111
|
+
if (uniqueKeysCache && (uniqueKeysCache as UniqueKeysCachePluggable).start) (uniqueKeysCache as UniqueKeysCachePluggable).start();
|
|
107
112
|
if (telemetry && (telemetry as ITelemetryCacheAsync).recordConfig) (telemetry as ITelemetryCacheAsync).recordConfig();
|
|
108
113
|
|
|
109
114
|
onReadyCb();
|
|
@@ -125,9 +130,9 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
125
130
|
|
|
126
131
|
// Stop periodic flush and disconnect the underlying storage
|
|
127
132
|
destroy() {
|
|
128
|
-
return Promise.all(
|
|
129
|
-
(impressionCountsCache as ImpressionCountsCachePluggable).stop && (impressionCountsCache as ImpressionCountsCachePluggable).stop(),
|
|
130
|
-
(uniqueKeysCache as UniqueKeysCachePluggable).stop && (uniqueKeysCache as UniqueKeysCachePluggable).stop(),
|
|
133
|
+
return Promise.all(isSyncronizer ? [] : [
|
|
134
|
+
impressionCountsCache && (impressionCountsCache as ImpressionCountsCachePluggable).stop && (impressionCountsCache as ImpressionCountsCachePluggable).stop(),
|
|
135
|
+
uniqueKeysCache && (uniqueKeysCache as UniqueKeysCachePluggable).stop && (uniqueKeysCache as UniqueKeysCachePluggable).stop(),
|
|
131
136
|
]).then(() => wrapper.disconnect());
|
|
132
137
|
},
|
|
133
138
|
|
package/src/storages/types.ts
CHANGED
|
@@ -191,8 +191,6 @@ export interface ISplitsCacheBase {
|
|
|
191
191
|
// only for Client-Side. Returns true if the storage is not synchronized yet (getChangeNumber() === -1) or contains a FF using segments or large segments
|
|
192
192
|
usesSegments(): MaybeThenable<boolean>,
|
|
193
193
|
clear(): MaybeThenable<boolean | void>,
|
|
194
|
-
// should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE.
|
|
195
|
-
checkCache(): MaybeThenable<boolean>,
|
|
196
194
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): MaybeThenable<boolean>,
|
|
197
195
|
getNamesByFlagSets(flagSets: string[]): MaybeThenable<Set<string>[]>
|
|
198
196
|
}
|
|
@@ -209,7 +207,6 @@ export interface ISplitsCacheSync extends ISplitsCacheBase {
|
|
|
209
207
|
trafficTypeExists(trafficType: string): boolean,
|
|
210
208
|
usesSegments(): boolean,
|
|
211
209
|
clear(): void,
|
|
212
|
-
checkCache(): boolean,
|
|
213
210
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean,
|
|
214
211
|
getNamesByFlagSets(flagSets: string[]): Set<string>[]
|
|
215
212
|
}
|
|
@@ -226,7 +223,6 @@ export interface ISplitsCacheAsync extends ISplitsCacheBase {
|
|
|
226
223
|
trafficTypeExists(trafficType: string): Promise<boolean>,
|
|
227
224
|
usesSegments(): Promise<boolean>,
|
|
228
225
|
clear(): Promise<boolean | void>,
|
|
229
|
-
checkCache(): Promise<boolean>,
|
|
230
226
|
killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise<boolean>,
|
|
231
227
|
getNamesByFlagSets(flagSets: string[]): Promise<Set<string>[]>
|
|
232
228
|
}
|
|
@@ -439,10 +435,10 @@ export interface IStorageBase<
|
|
|
439
435
|
splits: TSplitsCache,
|
|
440
436
|
segments: TSegmentsCache,
|
|
441
437
|
impressions: TImpressionsCache,
|
|
442
|
-
impressionCounts
|
|
438
|
+
impressionCounts?: TImpressionsCountCache,
|
|
443
439
|
events: TEventsCache,
|
|
444
440
|
telemetry?: TTelemetryCache,
|
|
445
|
-
uniqueKeys
|
|
441
|
+
uniqueKeys?: TUniqueKeysCache,
|
|
446
442
|
destroy(): void | Promise<void>,
|
|
447
443
|
shared?: (matchingKey: string, onReadyCb: (error?: any) => void) => this
|
|
448
444
|
}
|
|
@@ -457,6 +453,7 @@ export interface IStorageSync extends IStorageBase<
|
|
|
457
453
|
IUniqueKeysCacheSync
|
|
458
454
|
> {
|
|
459
455
|
// Defined in client-side
|
|
456
|
+
validateCache?: () => boolean, // @TODO support async
|
|
460
457
|
largeSegments?: ISegmentsCacheSync,
|
|
461
458
|
}
|
|
462
459
|
|