@splitsoftware/splitio-commons 2.3.0 → 2.3.1-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.txt +4 -0
- package/README.md +1 -0
- package/cjs/evaluator/Engine.js +40 -61
- package/cjs/evaluator/combiners/and.js +2 -6
- package/cjs/evaluator/combiners/ifelseif.js +6 -6
- package/cjs/evaluator/condition/index.js +6 -5
- package/cjs/evaluator/index.js +11 -11
- package/cjs/evaluator/matchers/index.js +3 -1
- package/cjs/evaluator/matchers/matcherTypes.js +1 -0
- package/cjs/evaluator/matchers/prerequisites.js +22 -0
- package/cjs/evaluator/matchers/rbsegment.js +56 -0
- package/cjs/evaluator/matchersTransform/index.js +4 -0
- package/cjs/evaluator/parser/index.js +2 -2
- package/cjs/evaluator/value/sanitize.js +1 -0
- package/cjs/logger/constants.js +5 -3
- package/cjs/logger/messages/debug.js +4 -2
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/sdkManager/index.js +2 -1
- package/cjs/services/splitApi.js +3 -4
- package/cjs/services/splitHttpClient.js +1 -1
- package/cjs/storages/AbstractSplitsCacheSync.js +5 -2
- package/cjs/storages/KeyBuilder.js +9 -0
- package/cjs/storages/KeyBuilderCS.js +3 -0
- package/cjs/storages/KeyBuilderSS.js +3 -0
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +117 -0
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +9 -14
- package/cjs/storages/inLocalStorage/index.js +5 -1
- package/cjs/storages/inLocalStorage/validateCache.js +2 -1
- package/cjs/storages/inMemory/InMemoryStorage.js +3 -0
- package/cjs/storages/inMemory/InMemoryStorageCS.js +4 -0
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +61 -0
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +1 -0
- package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +64 -0
- package/cjs/storages/inRedis/index.js +2 -0
- package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +64 -0
- package/cjs/storages/pluggable/index.js +2 -0
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +54 -4
- package/cjs/sync/polling/pollingManagerCS.js +7 -7
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +59 -33
- package/cjs/sync/streaming/SSEHandler/index.js +1 -0
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +106 -77
- package/cjs/sync/streaming/constants.js +2 -1
- package/cjs/sync/streaming/pushManager.js +3 -16
- package/cjs/sync/syncManagerOnline.js +2 -2
- package/cjs/utils/constants/index.js +6 -2
- package/cjs/utils/labels/index.js +2 -1
- package/esm/evaluator/Engine.js +40 -62
- package/esm/evaluator/combiners/and.js +2 -6
- package/esm/evaluator/combiners/ifelseif.js +7 -7
- package/esm/evaluator/condition/index.js +6 -5
- package/esm/evaluator/index.js +12 -12
- package/esm/evaluator/matchers/index.js +3 -1
- package/esm/evaluator/matchers/matcherTypes.js +1 -0
- package/esm/evaluator/matchers/prerequisites.js +18 -0
- package/esm/evaluator/matchers/rbsegment.js +52 -0
- package/esm/evaluator/matchersTransform/index.js +4 -0
- package/esm/evaluator/parser/index.js +2 -2
- package/esm/evaluator/value/sanitize.js +1 -0
- package/esm/logger/constants.js +2 -0
- package/esm/logger/messages/debug.js +4 -2
- package/esm/logger/messages/warn.js +1 -1
- package/esm/sdkManager/index.js +2 -1
- package/esm/services/splitApi.js +3 -4
- package/esm/services/splitHttpClient.js +1 -1
- package/esm/storages/AbstractSplitsCacheSync.js +5 -2
- package/esm/storages/KeyBuilder.js +9 -0
- package/esm/storages/KeyBuilderCS.js +3 -0
- package/esm/storages/KeyBuilderSS.js +3 -0
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +114 -0
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +9 -14
- package/esm/storages/inLocalStorage/index.js +5 -1
- package/esm/storages/inLocalStorage/validateCache.js +2 -1
- package/esm/storages/inMemory/InMemoryStorage.js +3 -0
- package/esm/storages/inMemory/InMemoryStorageCS.js +4 -0
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +58 -0
- package/esm/storages/inMemory/SplitsCacheInMemory.js +1 -0
- package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +61 -0
- package/esm/storages/inRedis/index.js +2 -0
- package/esm/storages/pluggable/RBSegmentsCachePluggable.js +61 -0
- package/esm/storages/pluggable/index.js +2 -0
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +54 -4
- package/esm/sync/polling/pollingManagerCS.js +7 -7
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/esm/sync/polling/updaters/splitChangesUpdater.js +59 -33
- package/esm/sync/streaming/SSEHandler/index.js +2 -1
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +102 -73
- package/esm/sync/streaming/constants.js +1 -0
- package/esm/sync/streaming/pushManager.js +6 -19
- package/esm/sync/syncManagerOnline.js +2 -2
- package/esm/utils/constants/index.js +5 -1
- package/esm/utils/labels/index.js +1 -0
- package/package.json +1 -1
- package/src/dtos/types.ts +41 -8
- package/src/evaluator/Engine.ts +42 -69
- package/src/evaluator/combiners/and.ts +5 -4
- package/src/evaluator/combiners/ifelseif.ts +7 -9
- package/src/evaluator/condition/engineUtils.ts +1 -1
- package/src/evaluator/condition/index.ts +12 -12
- package/src/evaluator/index.ts +12 -14
- package/src/evaluator/matchers/index.ts +3 -1
- package/src/evaluator/matchers/matcherTypes.ts +1 -0
- package/src/evaluator/matchers/prerequisites.ts +24 -0
- package/src/evaluator/matchers/rbsegment.ts +74 -0
- package/src/evaluator/matchersTransform/index.ts +3 -0
- package/src/evaluator/parser/index.ts +3 -3
- package/src/evaluator/types.ts +2 -2
- package/src/evaluator/value/index.ts +2 -2
- package/src/evaluator/value/sanitize.ts +5 -4
- package/src/logger/constants.ts +2 -0
- package/src/logger/messages/debug.ts +4 -2
- package/src/logger/messages/warn.ts +1 -1
- package/src/sdkManager/index.ts +3 -2
- package/src/services/splitApi.ts +3 -4
- package/src/services/splitHttpClient.ts +1 -1
- package/src/services/types.ts +1 -1
- package/src/storages/AbstractSplitsCacheSync.ts +6 -3
- package/src/storages/KeyBuilder.ts +12 -0
- package/src/storages/KeyBuilderCS.ts +4 -0
- package/src/storages/KeyBuilderSS.ts +4 -0
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +136 -0
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +10 -14
- package/src/storages/inLocalStorage/index.ts +5 -1
- package/src/storages/inLocalStorage/validateCache.ts +3 -1
- package/src/storages/inMemory/InMemoryStorage.ts +3 -0
- package/src/storages/inMemory/InMemoryStorageCS.ts +4 -0
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +68 -0
- package/src/storages/inMemory/SplitsCacheInMemory.ts +1 -0
- package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +79 -0
- package/src/storages/inRedis/index.ts +2 -0
- package/src/storages/pluggable/RBSegmentsCachePluggable.ts +76 -0
- package/src/storages/pluggable/index.ts +2 -0
- package/src/storages/types.ts +33 -1
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +65 -4
- package/src/sync/polling/fetchers/types.ts +1 -0
- package/src/sync/polling/pollingManagerCS.ts +7 -7
- package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -1
- package/src/sync/polling/types.ts +2 -2
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -2
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
- package/src/sync/polling/updaters/splitChangesUpdater.ts +70 -43
- package/src/sync/streaming/SSEHandler/index.ts +2 -1
- package/src/sync/streaming/SSEHandler/types.ts +2 -2
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +98 -68
- package/src/sync/streaming/constants.ts +1 -0
- package/src/sync/streaming/parseUtils.ts +2 -2
- package/src/sync/streaming/pushManager.ts +6 -18
- package/src/sync/streaming/types.ts +3 -2
- package/src/sync/syncManagerOnline.ts +2 -2
- package/src/utils/constants/index.ts +6 -1
- package/src/utils/labels/index.ts +1 -0
- package/src/utils/lang/index.ts +1 -1
- package/types/splitio.d.ts +5 -1
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { IRBSegment } from '../../dtos/types';
|
|
2
|
+
import { ILogger } from '../../logger/types';
|
|
3
|
+
import { ISettings } from '../../types';
|
|
4
|
+
import { isFiniteNumber, isNaNNumber, toNumber } from '../../utils/lang';
|
|
5
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
6
|
+
import { usesSegments } from '../AbstractSplitsCacheSync';
|
|
7
|
+
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
8
|
+
import { IRBSegmentsCacheSync } from '../types';
|
|
9
|
+
import { LOG_PREFIX } from './constants';
|
|
10
|
+
|
|
11
|
+
export class RBSegmentsCacheInLocal implements IRBSegmentsCacheSync {
|
|
12
|
+
|
|
13
|
+
private readonly keys: KeyBuilderCS;
|
|
14
|
+
private readonly log: ILogger;
|
|
15
|
+
|
|
16
|
+
constructor(settings: ISettings, keys: KeyBuilderCS) {
|
|
17
|
+
this.keys = keys;
|
|
18
|
+
this.log = settings.log;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
clear() {
|
|
22
|
+
this.getNames().forEach(name => this.remove(name));
|
|
23
|
+
localStorage.removeItem(this.keys.buildRBSegmentsTillKey());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): boolean {
|
|
27
|
+
this.setChangeNumber(changeNumber);
|
|
28
|
+
const updated = toAdd.map(toAdd => this.add(toAdd)).some(result => result);
|
|
29
|
+
return toRemove.map(toRemove => this.remove(toRemove.name)).some(result => result) || updated;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private setChangeNumber(changeNumber: number) {
|
|
33
|
+
try {
|
|
34
|
+
localStorage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
|
|
35
|
+
localStorage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
|
|
36
|
+
} catch (e) {
|
|
37
|
+
this.log.error(LOG_PREFIX + e);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private updateSegmentCount(diff: number) {
|
|
42
|
+
const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
|
|
43
|
+
const count = toNumber(localStorage.getItem(segmentsCountKey)) + diff;
|
|
44
|
+
// @ts-expect-error
|
|
45
|
+
if (count > 0) localStorage.setItem(segmentsCountKey, count);
|
|
46
|
+
else localStorage.removeItem(segmentsCountKey);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private add(rbSegment: IRBSegment): boolean {
|
|
50
|
+
try {
|
|
51
|
+
const name = rbSegment.name;
|
|
52
|
+
const rbSegmentKey = this.keys.buildRBSegmentKey(name);
|
|
53
|
+
const rbSegmentFromLocalStorage = localStorage.getItem(rbSegmentKey);
|
|
54
|
+
const previous = rbSegmentFromLocalStorage ? JSON.parse(rbSegmentFromLocalStorage) : null;
|
|
55
|
+
|
|
56
|
+
localStorage.setItem(rbSegmentKey, JSON.stringify(rbSegment));
|
|
57
|
+
|
|
58
|
+
let usesSegmentsDiff = 0;
|
|
59
|
+
if (previous && usesSegments(previous)) usesSegmentsDiff--;
|
|
60
|
+
if (usesSegments(rbSegment)) usesSegmentsDiff++;
|
|
61
|
+
if (usesSegmentsDiff !== 0) this.updateSegmentCount(usesSegmentsDiff);
|
|
62
|
+
|
|
63
|
+
return true;
|
|
64
|
+
} catch (e) {
|
|
65
|
+
this.log.error(LOG_PREFIX + e);
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private remove(name: string): boolean {
|
|
71
|
+
try {
|
|
72
|
+
const rbSegment = this.get(name);
|
|
73
|
+
if (!rbSegment) return false;
|
|
74
|
+
|
|
75
|
+
localStorage.removeItem(this.keys.buildRBSegmentKey(name));
|
|
76
|
+
|
|
77
|
+
if (usesSegments(rbSegment)) this.updateSegmentCount(-1);
|
|
78
|
+
|
|
79
|
+
return true;
|
|
80
|
+
} catch (e) {
|
|
81
|
+
this.log.error(LOG_PREFIX + e);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private getNames(): string[] {
|
|
87
|
+
const len = localStorage.length;
|
|
88
|
+
const accum = [];
|
|
89
|
+
|
|
90
|
+
let cur = 0;
|
|
91
|
+
|
|
92
|
+
while (cur < len) {
|
|
93
|
+
const key = localStorage.key(cur);
|
|
94
|
+
|
|
95
|
+
if (key != null && this.keys.isRBSegmentKey(key)) accum.push(this.keys.extractKey(key));
|
|
96
|
+
|
|
97
|
+
cur++;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return accum;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get(name: string): IRBSegment | null {
|
|
104
|
+
const item = localStorage.getItem(this.keys.buildRBSegmentKey(name));
|
|
105
|
+
return item && JSON.parse(item);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
contains(names: Set<string>): boolean {
|
|
109
|
+
const namesArray = setToArray(names);
|
|
110
|
+
const namesInStorage = this.getNames();
|
|
111
|
+
return namesArray.every(name => namesInStorage.indexOf(name) !== -1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
getChangeNumber(): number {
|
|
115
|
+
const n = -1;
|
|
116
|
+
let value: string | number | null = localStorage.getItem(this.keys.buildRBSegmentsTillKey());
|
|
117
|
+
|
|
118
|
+
if (value !== null) {
|
|
119
|
+
value = parseInt(value, 10);
|
|
120
|
+
|
|
121
|
+
return isNaNNumber(value) ? n : value;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return n;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
usesSegments(): boolean {
|
|
128
|
+
const storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
|
|
129
|
+
const splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
|
|
130
|
+
|
|
131
|
+
return isFiniteNumber(splitsWithSegmentsCount) ?
|
|
132
|
+
splitsWithSegmentsCount > 0 :
|
|
133
|
+
true;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
}
|
|
@@ -47,16 +47,14 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
47
47
|
|
|
48
48
|
private _incrementCounts(split: ISplit) {
|
|
49
49
|
try {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
localStorage.setItem(ttKey, toNumber(localStorage.getItem(ttKey)) + 1);
|
|
50
|
+
const ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
|
|
51
|
+
// @ts-expect-error
|
|
52
|
+
localStorage.setItem(ttKey, toNumber(localStorage.getItem(ttKey)) + 1);
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
54
|
+
if (usesSegments(split)) {
|
|
55
|
+
const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
|
|
56
|
+
// @ts-expect-error
|
|
57
|
+
localStorage.setItem(segmentsCountKey, toNumber(localStorage.getItem(segmentsCountKey)) + 1);
|
|
60
58
|
}
|
|
61
59
|
} catch (e) {
|
|
62
60
|
this.log.error(LOG_PREFIX + e);
|
|
@@ -185,11 +183,9 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
|
|
|
185
183
|
const storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
|
|
186
184
|
const splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
|
|
187
185
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return true;
|
|
192
|
-
}
|
|
186
|
+
return isFiniteNumber(splitsWithSegmentsCount) ?
|
|
187
|
+
splitsWithSegmentsCount > 0 :
|
|
188
|
+
true;
|
|
193
189
|
}
|
|
194
190
|
|
|
195
191
|
getNamesByFlagSets(flagSets: string[]): Set<string>[] {
|
|
@@ -6,6 +6,7 @@ import { validatePrefix } from '../KeyBuilder';
|
|
|
6
6
|
import { KeyBuilderCS, myLargeSegmentsKeyBuilder } from '../KeyBuilderCS';
|
|
7
7
|
import { isLocalStorageAvailable } from '../../utils/env/isLocalStorageAvailable';
|
|
8
8
|
import { SplitsCacheInLocal } from './SplitsCacheInLocal';
|
|
9
|
+
import { RBSegmentsCacheInLocal } from './RBSegmentsCacheInLocal';
|
|
9
10
|
import { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
|
|
10
11
|
import { InMemoryStorageCSFactory } from '../inMemory/InMemoryStorageCS';
|
|
11
12
|
import { LOG_PREFIX } from './constants';
|
|
@@ -36,11 +37,13 @@ export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): ISt
|
|
|
36
37
|
const keys = new KeyBuilderCS(prefix, matchingKey);
|
|
37
38
|
|
|
38
39
|
const splits = new SplitsCacheInLocal(settings, keys);
|
|
40
|
+
const rbSegments = new RBSegmentsCacheInLocal(settings, keys);
|
|
39
41
|
const segments = new MySegmentsCacheInLocal(log, keys);
|
|
40
42
|
const largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey));
|
|
41
43
|
|
|
42
44
|
return {
|
|
43
45
|
splits,
|
|
46
|
+
rbSegments,
|
|
44
47
|
segments,
|
|
45
48
|
largeSegments,
|
|
46
49
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
@@ -50,7 +53,7 @@ export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): ISt
|
|
|
50
53
|
uniqueKeys: new UniqueKeysCacheInMemoryCS(),
|
|
51
54
|
|
|
52
55
|
validateCache() {
|
|
53
|
-
return validateCache(options, settings, keys, splits, segments, largeSegments);
|
|
56
|
+
return validateCache(options, settings, keys, splits, rbSegments, segments, largeSegments);
|
|
54
57
|
},
|
|
55
58
|
|
|
56
59
|
destroy() { },
|
|
@@ -60,6 +63,7 @@ export function InLocalStorage(options: SplitIO.InLocalStorageOptions = {}): ISt
|
|
|
60
63
|
|
|
61
64
|
return {
|
|
62
65
|
splits: this.splits,
|
|
66
|
+
rbSegments: this.rbSegments,
|
|
63
67
|
segments: new MySegmentsCacheInLocal(log, new KeyBuilderCS(prefix, matchingKey)),
|
|
64
68
|
largeSegments: new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey)),
|
|
65
69
|
impressions: this.impressions,
|
|
@@ -3,6 +3,7 @@ import { isFiniteNumber, isNaNNumber } from '../../utils/lang';
|
|
|
3
3
|
import { getStorageHash } from '../KeyBuilder';
|
|
4
4
|
import { LOG_PREFIX } from './constants';
|
|
5
5
|
import type { SplitsCacheInLocal } from './SplitsCacheInLocal';
|
|
6
|
+
import type { RBSegmentsCacheInLocal } from './RBSegmentsCacheInLocal';
|
|
6
7
|
import type { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
|
|
7
8
|
import { KeyBuilderCS } from '../KeyBuilderCS';
|
|
8
9
|
import SplitIO from '../../../types/splitio';
|
|
@@ -66,13 +67,14 @@ function validateExpiration(options: SplitIO.InLocalStorageOptions, settings: IS
|
|
|
66
67
|
*
|
|
67
68
|
* @returns `true` if cache is ready to be used, `false` otherwise (cache was cleared or there is no cache)
|
|
68
69
|
*/
|
|
69
|
-
export function validateCache(options: SplitIO.InLocalStorageOptions, settings: ISettings, keys: KeyBuilderCS, splits: SplitsCacheInLocal, segments: MySegmentsCacheInLocal, largeSegments: MySegmentsCacheInLocal): boolean {
|
|
70
|
+
export function validateCache(options: SplitIO.InLocalStorageOptions, settings: ISettings, keys: KeyBuilderCS, splits: SplitsCacheInLocal, rbSegments: RBSegmentsCacheInLocal, segments: MySegmentsCacheInLocal, largeSegments: MySegmentsCacheInLocal): boolean {
|
|
70
71
|
|
|
71
72
|
const currentTimestamp = Date.now();
|
|
72
73
|
const isThereCache = splits.getChangeNumber() > -1;
|
|
73
74
|
|
|
74
75
|
if (validateExpiration(options, settings, keys, currentTimestamp, isThereCache)) {
|
|
75
76
|
splits.clear();
|
|
77
|
+
rbSegments.clear();
|
|
76
78
|
segments.clear();
|
|
77
79
|
largeSegments.clear();
|
|
78
80
|
|
|
@@ -7,6 +7,7 @@ import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
|
|
|
7
7
|
import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
|
|
8
8
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
9
9
|
import { UniqueKeysCacheInMemory } from './UniqueKeysCacheInMemory';
|
|
10
|
+
import { RBSegmentsCacheInMemory } from './RBSegmentsCacheInMemory';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* InMemory storage factory for standalone server-side SplitFactory
|
|
@@ -17,10 +18,12 @@ export function InMemoryStorageFactory(params: IStorageFactoryParams): IStorageS
|
|
|
17
18
|
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { __splitFiltersValidation } } } = params;
|
|
18
19
|
|
|
19
20
|
const splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
21
|
+
const rbSegments = new RBSegmentsCacheInMemory();
|
|
20
22
|
const segments = new SegmentsCacheInMemory();
|
|
21
23
|
|
|
22
24
|
const storage = {
|
|
23
25
|
splits,
|
|
26
|
+
rbSegments,
|
|
24
27
|
segments,
|
|
25
28
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
26
29
|
impressionCounts: new ImpressionCountsCacheInMemory(),
|
|
@@ -7,6 +7,7 @@ import { ImpressionCountsCacheInMemory } from './ImpressionCountsCacheInMemory';
|
|
|
7
7
|
import { LOCALHOST_MODE, STORAGE_MEMORY } from '../../utils/constants';
|
|
8
8
|
import { shouldRecordTelemetry, TelemetryCacheInMemory } from './TelemetryCacheInMemory';
|
|
9
9
|
import { UniqueKeysCacheInMemoryCS } from './UniqueKeysCacheInMemoryCS';
|
|
10
|
+
import { RBSegmentsCacheInMemory } from './RBSegmentsCacheInMemory';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* InMemory storage factory for standalone client-side SplitFactory
|
|
@@ -17,11 +18,13 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
17
18
|
const { settings: { scheduler: { impressionsQueueSize, eventsQueueSize }, sync: { __splitFiltersValidation } } } = params;
|
|
18
19
|
|
|
19
20
|
const splits = new SplitsCacheInMemory(__splitFiltersValidation);
|
|
21
|
+
const rbSegments = new RBSegmentsCacheInMemory();
|
|
20
22
|
const segments = new MySegmentsCacheInMemory();
|
|
21
23
|
const largeSegments = new MySegmentsCacheInMemory();
|
|
22
24
|
|
|
23
25
|
const storage = {
|
|
24
26
|
splits,
|
|
27
|
+
rbSegments,
|
|
25
28
|
segments,
|
|
26
29
|
largeSegments,
|
|
27
30
|
impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
|
|
@@ -36,6 +39,7 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
|
|
|
36
39
|
shared() {
|
|
37
40
|
return {
|
|
38
41
|
splits: this.splits,
|
|
42
|
+
rbSegments: this.rbSegments,
|
|
39
43
|
segments: new MySegmentsCacheInMemory(),
|
|
40
44
|
largeSegments: new MySegmentsCacheInMemory(),
|
|
41
45
|
impressions: this.impressions,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { IRBSegment } from '../../dtos/types';
|
|
2
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
3
|
+
import { usesSegments } from '../AbstractSplitsCacheSync';
|
|
4
|
+
import { IRBSegmentsCacheSync } from '../types';
|
|
5
|
+
|
|
6
|
+
export class RBSegmentsCacheInMemory implements IRBSegmentsCacheSync {
|
|
7
|
+
|
|
8
|
+
private cache: Record<string, IRBSegment> = {};
|
|
9
|
+
private changeNumber: number = -1;
|
|
10
|
+
private segmentsCount: number = 0;
|
|
11
|
+
|
|
12
|
+
clear() {
|
|
13
|
+
this.cache = {};
|
|
14
|
+
this.changeNumber = -1;
|
|
15
|
+
this.segmentsCount = 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): boolean {
|
|
19
|
+
this.changeNumber = changeNumber;
|
|
20
|
+
const updated = toAdd.map(toAdd => this.add(toAdd)).some(result => result);
|
|
21
|
+
return toRemove.map(toRemove => this.remove(toRemove.name)).some(result => result) || updated;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private add(rbSegment: IRBSegment): boolean {
|
|
25
|
+
const name = rbSegment.name;
|
|
26
|
+
const previous = this.get(name);
|
|
27
|
+
if (previous && usesSegments(previous)) this.segmentsCount--;
|
|
28
|
+
|
|
29
|
+
this.cache[name] = rbSegment;
|
|
30
|
+
if (usesSegments(rbSegment)) this.segmentsCount++;
|
|
31
|
+
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private remove(name: string): boolean {
|
|
36
|
+
const rbSegment = this.get(name);
|
|
37
|
+
if (!rbSegment) return false;
|
|
38
|
+
|
|
39
|
+
delete this.cache[name];
|
|
40
|
+
|
|
41
|
+
if (usesSegments(rbSegment)) this.segmentsCount--;
|
|
42
|
+
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private getNames(): string[] {
|
|
47
|
+
return Object.keys(this.cache);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get(name: string): IRBSegment | null {
|
|
51
|
+
return this.cache[name] || null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
contains(names: Set<string>): boolean {
|
|
55
|
+
const namesArray = setToArray(names);
|
|
56
|
+
const namesInStorage = this.getNames();
|
|
57
|
+
return namesArray.every(name => namesInStorage.indexOf(name) !== -1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getChangeNumber(): number {
|
|
61
|
+
return this.changeNumber;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
usesSegments(): boolean {
|
|
65
|
+
return this.segmentsCount > 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { isNaNNumber } from '../../utils/lang';
|
|
2
|
+
import { IRBSegmentsCacheAsync } from '../types';
|
|
3
|
+
import { ILogger } from '../../logger/types';
|
|
4
|
+
import { IRBSegment } from '../../dtos/types';
|
|
5
|
+
import { LOG_PREFIX } from './constants';
|
|
6
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
7
|
+
import { RedisAdapter } from './RedisAdapter';
|
|
8
|
+
import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
9
|
+
|
|
10
|
+
export class RBSegmentsCacheInRedis implements IRBSegmentsCacheAsync {
|
|
11
|
+
|
|
12
|
+
private readonly log: ILogger;
|
|
13
|
+
private readonly keys: KeyBuilderSS;
|
|
14
|
+
private readonly redis: RedisAdapter;
|
|
15
|
+
|
|
16
|
+
constructor(log: ILogger, keys: KeyBuilderSS, redis: RedisAdapter) {
|
|
17
|
+
this.log = log;
|
|
18
|
+
this.keys = keys;
|
|
19
|
+
this.redis = redis;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get(name: string): Promise<IRBSegment | null> {
|
|
23
|
+
return this.redis.get(this.keys.buildRBSegmentKey(name))
|
|
24
|
+
.then(maybeRBSegment => maybeRBSegment && JSON.parse(maybeRBSegment));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private getNames(): Promise<string[]> {
|
|
28
|
+
return this.redis.keys(this.keys.searchPatternForRBSegmentKeys()).then(
|
|
29
|
+
(listOfKeys) => listOfKeys.map(this.keys.extractKey)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
contains(names: Set<string>): Promise<boolean> {
|
|
34
|
+
const namesArray = setToArray(names);
|
|
35
|
+
return this.getNames().then(namesInStorage => {
|
|
36
|
+
return namesArray.every(name => namesInStorage.includes(name));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): Promise<boolean> {
|
|
41
|
+
return Promise.all([
|
|
42
|
+
this.setChangeNumber(changeNumber),
|
|
43
|
+
Promise.all(toAdd.map(toAdd => {
|
|
44
|
+
const key = this.keys.buildRBSegmentKey(toAdd.name);
|
|
45
|
+
const stringifiedNewRBSegment = JSON.stringify(toAdd);
|
|
46
|
+
return this.redis.set(key, stringifiedNewRBSegment).then(() => true);
|
|
47
|
+
})),
|
|
48
|
+
Promise.all(toRemove.map(toRemove => {
|
|
49
|
+
const key = this.keys.buildRBSegmentKey(toRemove.name);
|
|
50
|
+
return this.redis.del(key).then(status => status === 1);
|
|
51
|
+
}))
|
|
52
|
+
]).then(([, added, removed]) => {
|
|
53
|
+
return added.some(result => result) || removed.some(result => result);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
setChangeNumber(changeNumber: number) {
|
|
58
|
+
return this.redis.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '').then(
|
|
59
|
+
status => status === 'OK'
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getChangeNumber(): Promise<number> {
|
|
64
|
+
return this.redis.get(this.keys.buildRBSegmentsTillKey()).then((value: string | null) => {
|
|
65
|
+
const i = parseInt(value as string, 10);
|
|
66
|
+
|
|
67
|
+
return isNaNNumber(i) ? -1 : i;
|
|
68
|
+
}).catch((e) => {
|
|
69
|
+
this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from storage. Error: ' + e);
|
|
70
|
+
return -1;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// @TODO implement if required by DataLoader or producer mode
|
|
75
|
+
clear() {
|
|
76
|
+
return Promise.resolve();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|
|
@@ -11,6 +11,7 @@ import { TelemetryCacheInRedis } from './TelemetryCacheInRedis';
|
|
|
11
11
|
import { UniqueKeysCacheInRedis } from './UniqueKeysCacheInRedis';
|
|
12
12
|
import { ImpressionCountsCacheInRedis } from './ImpressionCountsCacheInRedis';
|
|
13
13
|
import { metadataBuilder } from '../utils';
|
|
14
|
+
import { RBSegmentsCacheInRedis } from './RBSegmentsCacheInRedis';
|
|
14
15
|
|
|
15
16
|
export interface InRedisStorageOptions {
|
|
16
17
|
prefix?: string
|
|
@@ -59,6 +60,7 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
|
|
|
59
60
|
|
|
60
61
|
return {
|
|
61
62
|
splits: new SplitsCacheInRedis(log, keys, redisClient, settings.sync.__splitFiltersValidation),
|
|
63
|
+
rbSegments: new RBSegmentsCacheInRedis(log, keys, redisClient),
|
|
62
64
|
segments: new SegmentsCacheInRedis(log, keys, redisClient),
|
|
63
65
|
impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
|
|
64
66
|
impressionCounts: impressionCountsCache,
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { isNaNNumber } from '../../utils/lang';
|
|
2
|
+
import { KeyBuilder } from '../KeyBuilder';
|
|
3
|
+
import { IPluggableStorageWrapper, IRBSegmentsCacheAsync } from '../types';
|
|
4
|
+
import { ILogger } from '../../logger/types';
|
|
5
|
+
import { IRBSegment } from '../../dtos/types';
|
|
6
|
+
import { LOG_PREFIX } from './constants';
|
|
7
|
+
import { setToArray } from '../../utils/lang/sets';
|
|
8
|
+
|
|
9
|
+
export class RBSegmentsCachePluggable implements IRBSegmentsCacheAsync {
|
|
10
|
+
|
|
11
|
+
private readonly log: ILogger;
|
|
12
|
+
private readonly keys: KeyBuilder;
|
|
13
|
+
private readonly wrapper: IPluggableStorageWrapper;
|
|
14
|
+
|
|
15
|
+
constructor(log: ILogger, keys: KeyBuilder, wrapper: IPluggableStorageWrapper) {
|
|
16
|
+
this.log = log;
|
|
17
|
+
this.keys = keys;
|
|
18
|
+
this.wrapper = wrapper;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
get(name: string): Promise<IRBSegment | null> {
|
|
22
|
+
return this.wrapper.get(this.keys.buildRBSegmentKey(name))
|
|
23
|
+
.then(maybeRBSegment => maybeRBSegment && JSON.parse(maybeRBSegment));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private getNames(): Promise<string[]> {
|
|
27
|
+
return this.wrapper.getKeysByPrefix(this.keys.buildRBSegmentKeyPrefix()).then(
|
|
28
|
+
(listOfKeys) => listOfKeys.map(this.keys.extractKey)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
contains(names: Set<string>): Promise<boolean> {
|
|
33
|
+
const namesArray = setToArray(names);
|
|
34
|
+
return this.getNames().then(namesInStorage => {
|
|
35
|
+
return namesArray.every(name => namesInStorage.includes(name));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): Promise<boolean> {
|
|
40
|
+
return Promise.all([
|
|
41
|
+
this.setChangeNumber(changeNumber),
|
|
42
|
+
Promise.all(toAdd.map(toAdd => {
|
|
43
|
+
const key = this.keys.buildRBSegmentKey(toAdd.name);
|
|
44
|
+
const stringifiedNewRBSegment = JSON.stringify(toAdd);
|
|
45
|
+
return this.wrapper.set(key, stringifiedNewRBSegment).then(() => true);
|
|
46
|
+
})),
|
|
47
|
+
Promise.all(toRemove.map(toRemove => {
|
|
48
|
+
const key = this.keys.buildRBSegmentKey(toRemove.name);
|
|
49
|
+
return this.wrapper.del(key);
|
|
50
|
+
}))
|
|
51
|
+
]).then(([, added, removed]) => {
|
|
52
|
+
return added.some(result => result) || removed.some(result => result);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
setChangeNumber(changeNumber: number) {
|
|
57
|
+
return this.wrapper.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getChangeNumber(): Promise<number> {
|
|
61
|
+
return this.wrapper.get(this.keys.buildRBSegmentsTillKey()).then((value) => {
|
|
62
|
+
const i = parseInt(value as string, 10);
|
|
63
|
+
|
|
64
|
+
return isNaNNumber(i) ? -1 : i;
|
|
65
|
+
}).catch((e) => {
|
|
66
|
+
this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from storage. Error: ' + e);
|
|
67
|
+
return -1;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// @TODO implement if required by DataLoader or producer mode
|
|
72
|
+
clear() {
|
|
73
|
+
return Promise.resolve();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
}
|
|
@@ -20,6 +20,7 @@ import { UniqueKeysCacheInMemory } from '../inMemory/UniqueKeysCacheInMemory';
|
|
|
20
20
|
import { UniqueKeysCacheInMemoryCS } from '../inMemory/UniqueKeysCacheInMemoryCS';
|
|
21
21
|
import { metadataBuilder } from '../utils';
|
|
22
22
|
import { LOG_PREFIX } from '../pluggable/constants';
|
|
23
|
+
import { RBSegmentsCachePluggable } from './RBSegmentsCachePluggable';
|
|
23
24
|
|
|
24
25
|
const NO_VALID_WRAPPER = 'Expecting pluggable storage `wrapper` in options, but no valid wrapper instance was provided.';
|
|
25
26
|
const NO_VALID_WRAPPER_INTERFACE = 'The provided wrapper instance doesn’t follow the expected interface. Check our docs.';
|
|
@@ -117,6 +118,7 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
117
118
|
|
|
118
119
|
return {
|
|
119
120
|
splits: new SplitsCachePluggable(log, keys, wrapper, settings.sync.__splitFiltersValidation),
|
|
121
|
+
rbSegments: new RBSegmentsCachePluggable(log, keys, wrapper),
|
|
120
122
|
segments: new SegmentsCachePluggable(log, keys, wrapper),
|
|
121
123
|
impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
|
|
122
124
|
impressionCounts: impressionCountsCache,
|
package/src/storages/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import SplitIO from '../../types/splitio';
|
|
2
|
-
import { MaybeThenable, ISplit, IMySegmentsResponse } from '../dtos/types';
|
|
2
|
+
import { MaybeThenable, ISplit, IRBSegment, IMySegmentsResponse } from '../dtos/types';
|
|
3
3
|
import { MySegmentsData } from '../sync/polling/types';
|
|
4
4
|
import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, MultiMethodExceptions, MultiMethodLatencies, MultiConfigs, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent, UniqueKeysPayloadCs, UniqueKeysPayloadSs, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../sync/submitters/types';
|
|
5
5
|
import { ISettings } from '../types';
|
|
@@ -221,6 +221,34 @@ export interface ISplitsCacheAsync extends ISplitsCacheBase {
|
|
|
221
221
|
getNamesByFlagSets(flagSets: string[]): Promise<Set<string>[]>
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
/** Rule-Based Segments cache */
|
|
225
|
+
|
|
226
|
+
export interface IRBSegmentsCacheBase {
|
|
227
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): MaybeThenable<boolean>,
|
|
228
|
+
get(name: string): MaybeThenable<IRBSegment | null>,
|
|
229
|
+
getChangeNumber(): MaybeThenable<number>,
|
|
230
|
+
clear(): MaybeThenable<boolean | void>,
|
|
231
|
+
contains(names: Set<string>): MaybeThenable<boolean>,
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface IRBSegmentsCacheSync extends IRBSegmentsCacheBase {
|
|
235
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): boolean,
|
|
236
|
+
get(name: string): IRBSegment | null,
|
|
237
|
+
getChangeNumber(): number,
|
|
238
|
+
clear(): void,
|
|
239
|
+
contains(names: Set<string>): boolean,
|
|
240
|
+
// Used only for smart pausing in client-side standalone. Returns true if the storage contains a RBSegment using segments or large segments matchers
|
|
241
|
+
usesSegments(): boolean,
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export interface IRBSegmentsCacheAsync extends IRBSegmentsCacheBase {
|
|
245
|
+
update(toAdd: IRBSegment[], toRemove: IRBSegment[], changeNumber: number): Promise<boolean>,
|
|
246
|
+
get(name: string): Promise<IRBSegment | null>,
|
|
247
|
+
getChangeNumber(): Promise<number>,
|
|
248
|
+
clear(): Promise<boolean | void>,
|
|
249
|
+
contains(names: Set<string>): Promise<boolean>,
|
|
250
|
+
}
|
|
251
|
+
|
|
224
252
|
/** Segments cache */
|
|
225
253
|
|
|
226
254
|
export interface ISegmentsCacheBase {
|
|
@@ -419,6 +447,7 @@ export interface ITelemetryCacheAsync extends ITelemetryEvaluationProducerAsync,
|
|
|
419
447
|
|
|
420
448
|
export interface IStorageBase<
|
|
421
449
|
TSplitsCache extends ISplitsCacheBase = ISplitsCacheBase,
|
|
450
|
+
TRBSegmentsCache extends IRBSegmentsCacheBase = IRBSegmentsCacheBase,
|
|
422
451
|
TSegmentsCache extends ISegmentsCacheBase = ISegmentsCacheBase,
|
|
423
452
|
TImpressionsCache extends IImpressionsCacheBase = IImpressionsCacheBase,
|
|
424
453
|
TImpressionsCountCache extends IImpressionCountsCacheBase = IImpressionCountsCacheBase,
|
|
@@ -427,6 +456,7 @@ export interface IStorageBase<
|
|
|
427
456
|
TUniqueKeysCache extends IUniqueKeysCacheBase = IUniqueKeysCacheBase
|
|
428
457
|
> {
|
|
429
458
|
splits: TSplitsCache,
|
|
459
|
+
rbSegments: TRBSegmentsCache,
|
|
430
460
|
segments: TSegmentsCache,
|
|
431
461
|
impressions: TImpressionsCache,
|
|
432
462
|
impressionCounts: TImpressionsCountCache,
|
|
@@ -439,6 +469,7 @@ export interface IStorageBase<
|
|
|
439
469
|
|
|
440
470
|
export interface IStorageSync extends IStorageBase<
|
|
441
471
|
ISplitsCacheSync,
|
|
472
|
+
IRBSegmentsCacheSync,
|
|
442
473
|
ISegmentsCacheSync,
|
|
443
474
|
IImpressionsCacheSync,
|
|
444
475
|
IImpressionCountsCacheSync,
|
|
@@ -453,6 +484,7 @@ export interface IStorageSync extends IStorageBase<
|
|
|
453
484
|
|
|
454
485
|
export interface IStorageAsync extends IStorageBase<
|
|
455
486
|
ISplitsCacheAsync,
|
|
487
|
+
IRBSegmentsCacheAsync,
|
|
456
488
|
ISegmentsCacheAsync,
|
|
457
489
|
IImpressionsCacheAsync | IImpressionsCacheSync,
|
|
458
490
|
IImpressionCountsCacheBase,
|