@splitsoftware/splitio-commons 2.1.1-rc.0 → 2.1.1-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 +3 -0
- package/README.md +0 -1
- package/cjs/evaluator/combiners/and.js +6 -2
- package/cjs/evaluator/combiners/ifelseif.js +6 -6
- package/cjs/evaluator/condition/index.js +5 -6
- package/cjs/evaluator/index.js +7 -7
- package/cjs/evaluator/matchers/index.js +1 -3
- package/cjs/evaluator/matchers/matcherTypes.js +0 -1
- package/cjs/evaluator/matchersTransform/index.js +0 -4
- package/cjs/evaluator/parser/index.js +2 -2
- package/cjs/evaluator/value/sanitize.js +0 -1
- package/cjs/logger/constants.js +3 -4
- package/cjs/logger/messages/debug.js +2 -3
- package/cjs/logger/messages/error.js +1 -1
- package/cjs/logger/messages/warn.js +2 -2
- package/cjs/sdkClient/client.js +29 -19
- package/cjs/sdkClient/clientAttributesDecoration.js +19 -25
- package/cjs/sdkClient/clientInputValidation.js +28 -26
- package/cjs/services/splitApi.js +2 -2
- package/cjs/storages/AbstractSplitsCacheSync.js +2 -5
- package/cjs/storages/KeyBuilder.js +0 -9
- package/cjs/storages/KeyBuilderCS.js +1 -4
- package/cjs/storages/KeyBuilderSS.js +0 -3
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +14 -9
- package/cjs/storages/inLocalStorage/index.js +0 -4
- package/cjs/storages/inMemory/InMemoryStorage.js +0 -3
- package/cjs/storages/inMemory/InMemoryStorageCS.js +0 -4
- package/cjs/storages/inRedis/index.js +0 -2
- package/cjs/storages/pluggable/index.js +0 -2
- package/cjs/storages/utils.js +1 -0
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +2 -2
- package/cjs/sync/polling/pollingManagerCS.js +7 -7
- 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 +35 -51
- package/cjs/sync/streaming/SSEHandler/index.js +0 -1
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +77 -106
- package/cjs/sync/streaming/constants.js +1 -2
- package/cjs/sync/streaming/pushManager.js +16 -3
- package/cjs/sync/submitters/impressionsSubmitter.js +3 -2
- package/cjs/sync/syncManagerOnline.js +2 -2
- package/cjs/trackers/strategy/strategyOptimized.js +3 -0
- package/cjs/utils/constants/index.js +2 -3
- package/cjs/utils/inputValidation/eventProperties.js +12 -1
- package/cjs/utils/inputValidation/index.js +3 -1
- package/esm/evaluator/combiners/and.js +6 -2
- package/esm/evaluator/combiners/ifelseif.js +7 -7
- package/esm/evaluator/condition/index.js +5 -6
- package/esm/evaluator/index.js +7 -7
- package/esm/evaluator/matchers/index.js +1 -3
- package/esm/evaluator/matchers/matcherTypes.js +0 -1
- package/esm/evaluator/matchersTransform/index.js +0 -4
- package/esm/evaluator/parser/index.js +2 -2
- package/esm/evaluator/value/sanitize.js +0 -1
- package/esm/logger/constants.js +0 -1
- package/esm/logger/messages/debug.js +2 -3
- package/esm/logger/messages/error.js +1 -1
- package/esm/logger/messages/warn.js +2 -2
- package/esm/sdkClient/client.js +29 -19
- package/esm/sdkClient/clientAttributesDecoration.js +19 -25
- package/esm/sdkClient/clientInputValidation.js +29 -27
- package/esm/services/splitApi.js +2 -2
- package/esm/storages/AbstractSplitsCacheSync.js +2 -5
- package/esm/storages/KeyBuilder.js +0 -9
- package/esm/storages/KeyBuilderCS.js +1 -4
- package/esm/storages/KeyBuilderSS.js +0 -3
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +14 -9
- package/esm/storages/inLocalStorage/index.js +0 -4
- package/esm/storages/inMemory/InMemoryStorage.js +0 -3
- package/esm/storages/inMemory/InMemoryStorageCS.js +0 -4
- package/esm/storages/inRedis/index.js +0 -2
- package/esm/storages/pluggable/index.js +0 -2
- package/esm/storages/utils.js +1 -0
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +2 -2
- package/esm/sync/polling/pollingManagerCS.js +7 -7
- 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 +35 -51
- package/esm/sync/streaming/SSEHandler/index.js +1 -2
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +73 -102
- package/esm/sync/streaming/constants.js +0 -1
- package/esm/sync/streaming/pushManager.js +19 -6
- package/esm/sync/submitters/impressionsSubmitter.js +3 -2
- package/esm/sync/syncManagerOnline.js +2 -2
- package/esm/trackers/strategy/strategyOptimized.js +3 -0
- package/esm/utils/constants/index.js +1 -2
- package/esm/utils/inputValidation/eventProperties.js +10 -0
- package/esm/utils/inputValidation/index.js +1 -0
- package/package.json +1 -1
- package/src/dtos/types.ts +8 -32
- package/src/evaluator/Engine.ts +1 -1
- package/src/evaluator/combiners/and.ts +4 -5
- package/src/evaluator/combiners/ifelseif.ts +9 -7
- package/src/evaluator/condition/engineUtils.ts +1 -1
- package/src/evaluator/condition/index.ts +12 -12
- package/src/evaluator/index.ts +7 -7
- package/src/evaluator/matchers/index.ts +1 -3
- package/src/evaluator/matchers/matcherTypes.ts +0 -1
- package/src/evaluator/matchersTransform/index.ts +0 -3
- 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 +4 -5
- package/src/logger/constants.ts +0 -1
- package/src/logger/messages/debug.ts +2 -3
- package/src/logger/messages/error.ts +1 -1
- package/src/logger/messages/warn.ts +2 -2
- package/src/sdkClient/client.ts +31 -21
- package/src/sdkClient/clientAttributesDecoration.ts +20 -27
- package/src/sdkClient/clientInputValidation.ts +30 -27
- package/src/sdkManager/index.ts +1 -1
- package/src/services/splitApi.ts +2 -2
- package/src/services/types.ts +1 -1
- package/src/storages/AbstractSplitsCacheSync.ts +3 -6
- package/src/storages/KeyBuilder.ts +0 -12
- package/src/storages/KeyBuilderCS.ts +1 -5
- package/src/storages/KeyBuilderSS.ts +0 -4
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +14 -10
- package/src/storages/inLocalStorage/index.ts +0 -4
- package/src/storages/inMemory/InMemoryStorage.ts +0 -3
- package/src/storages/inMemory/InMemoryStorageCS.ts +0 -4
- package/src/storages/inRedis/index.ts +0 -2
- package/src/storages/pluggable/index.ts +0 -2
- package/src/storages/types.ts +1 -33
- package/src/storages/utils.ts +1 -0
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +1 -2
- package/src/sync/polling/fetchers/types.ts +0 -1
- package/src/sync/polling/pollingManagerCS.ts +7 -7
- 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 +44 -61
- package/src/sync/streaming/SSEHandler/index.ts +1 -2
- package/src/sync/streaming/SSEHandler/types.ts +2 -2
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +68 -98
- package/src/sync/streaming/constants.ts +0 -1
- package/src/sync/streaming/parseUtils.ts +2 -2
- package/src/sync/streaming/pushManager.ts +18 -6
- package/src/sync/streaming/types.ts +2 -3
- package/src/sync/submitters/impressionsSubmitter.ts +3 -2
- package/src/sync/submitters/types.ts +23 -33
- package/src/sync/syncManagerOnline.ts +2 -2
- package/src/trackers/strategy/strategyOptimized.ts +3 -0
- package/src/utils/constants/index.ts +1 -2
- package/src/utils/inputValidation/eventProperties.ts +10 -0
- package/src/utils/inputValidation/index.ts +1 -0
- package/src/utils/lang/index.ts +1 -1
- package/types/splitio.d.ts +100 -35
- package/cjs/evaluator/matchers/rbsegment.js +0 -43
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +0 -117
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +0 -61
- package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +0 -64
- package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +0 -64
- package/esm/evaluator/matchers/rbsegment.js +0 -39
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +0 -114
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +0 -58
- package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +0 -61
- package/esm/storages/pluggable/RBSegmentsCachePluggable.js +0 -61
- package/src/evaluator/matchers/rbsegment.ts +0 -61
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +0 -136
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +0 -68
- package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +0 -79
- package/src/storages/pluggable/RBSegmentsCachePluggable.ts +0 -76
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { ISegmentsCacheBase, IStorageBase } from '../../../storages/types';
|
|
2
2
|
import { ISplitChangesFetcher } from '../fetchers/types';
|
|
3
|
-
import {
|
|
3
|
+
import { ISplit, ISplitChangesResponse, ISplitFiltersValidation } from '../../../dtos/types';
|
|
4
4
|
import { ISplitsEventEmitter } from '../../../readiness/types';
|
|
5
5
|
import { timeout } from '../../../utils/promise/timeout';
|
|
6
6
|
import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
|
|
7
7
|
import { ILogger } from '../../../logger/types';
|
|
8
|
-
import { SYNC_SPLITS_FETCH, SYNC_SPLITS_UPDATE,
|
|
8
|
+
import { SYNC_SPLITS_FETCH, SYNC_SPLITS_UPDATE, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
|
|
9
9
|
import { startsWith } from '../../../utils/lang';
|
|
10
|
-
import {
|
|
10
|
+
import { IN_SEGMENT } from '../../../utils/constants';
|
|
11
11
|
import { setToArray } from '../../../utils/lang/sets';
|
|
12
|
-
import { SPLIT_UPDATE } from '../../streaming/constants';
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
type SplitChangesUpdater = (noCache?: boolean, till?: number, instantUpdate?: InstantUpdate) => Promise<boolean>
|
|
13
|
+
type ISplitChangesUpdater = (noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }) => Promise<boolean>
|
|
16
14
|
|
|
17
15
|
// Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
|
|
18
16
|
// Returns a promise that could be rejected.
|
|
@@ -29,24 +27,24 @@ function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
|
|
|
29
27
|
* Collect segments from a raw split definition.
|
|
30
28
|
* Exported for testing purposes.
|
|
31
29
|
*/
|
|
32
|
-
export function parseSegments(
|
|
33
|
-
|
|
34
|
-
const segments = new Set<string>(excluded && excluded.segments);
|
|
30
|
+
export function parseSegments({ conditions }: ISplit): Set<string> {
|
|
31
|
+
let segments = new Set<string>();
|
|
35
32
|
|
|
36
33
|
for (let i = 0; i < conditions.length; i++) {
|
|
37
34
|
const matchers = conditions[i].matcherGroup.matchers;
|
|
38
35
|
|
|
39
36
|
matchers.forEach(matcher => {
|
|
40
|
-
if (matcher.matcherType ===
|
|
37
|
+
if (matcher.matcherType === IN_SEGMENT) segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
|
|
41
38
|
});
|
|
42
39
|
}
|
|
43
40
|
|
|
44
41
|
return segments;
|
|
45
42
|
}
|
|
46
43
|
|
|
47
|
-
interface ISplitMutations
|
|
48
|
-
added:
|
|
49
|
-
removed:
|
|
44
|
+
interface ISplitMutations {
|
|
45
|
+
added: ISplit[],
|
|
46
|
+
removed: ISplit[],
|
|
47
|
+
segments: string[]
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
/**
|
|
@@ -75,21 +73,25 @@ function matchFilters(featureFlag: ISplit, filters: ISplitFiltersValidation) {
|
|
|
75
73
|
* i.e., an object with added splits, removed splits and used segments.
|
|
76
74
|
* Exported for testing purposes.
|
|
77
75
|
*/
|
|
78
|
-
export function
|
|
76
|
+
export function computeSplitsMutation(entries: ISplit[], filters: ISplitFiltersValidation): ISplitMutations {
|
|
77
|
+
const segments = new Set<string>();
|
|
78
|
+
const computed = entries.reduce((accum, split) => {
|
|
79
|
+
if (split.status === 'ACTIVE' && matchFilters(split, filters)) {
|
|
80
|
+
accum.added.push(split);
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
if (ruleEntity.status === 'ACTIVE' && (!filters || matchFilters(ruleEntity as ISplit, filters))) {
|
|
82
|
-
accum.added.push(ruleEntity);
|
|
83
|
-
|
|
84
|
-
parseSegments(ruleEntity).forEach((segmentName: string) => {
|
|
82
|
+
parseSegments(split).forEach((segmentName: string) => {
|
|
85
83
|
segments.add(segmentName);
|
|
86
84
|
});
|
|
87
85
|
} else {
|
|
88
|
-
accum.removed.push(
|
|
86
|
+
accum.removed.push(split);
|
|
89
87
|
}
|
|
90
88
|
|
|
91
89
|
return accum;
|
|
92
|
-
}, { added: [], removed: [] } as ISplitMutations
|
|
90
|
+
}, { added: [], removed: [], segments: [] } as ISplitMutations);
|
|
91
|
+
|
|
92
|
+
computed.segments = setToArray(segments);
|
|
93
|
+
|
|
94
|
+
return computed;
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
/**
|
|
@@ -109,14 +111,14 @@ export function computeMutation<T extends ISplit | IRBSegment>(rules: Array<T>,
|
|
|
109
111
|
export function splitChangesUpdaterFactory(
|
|
110
112
|
log: ILogger,
|
|
111
113
|
splitChangesFetcher: ISplitChangesFetcher,
|
|
112
|
-
storage: Pick<IStorageBase, 'splits' | '
|
|
114
|
+
storage: Pick<IStorageBase, 'splits' | 'segments'>,
|
|
113
115
|
splitFiltersValidation: ISplitFiltersValidation,
|
|
114
116
|
splitsEventEmitter?: ISplitsEventEmitter,
|
|
115
117
|
requestTimeoutBeforeReady: number = 0,
|
|
116
118
|
retriesOnFailureBeforeReady: number = 0,
|
|
117
119
|
isClientSide?: boolean
|
|
118
|
-
):
|
|
119
|
-
const { splits,
|
|
120
|
+
): ISplitChangesUpdater {
|
|
121
|
+
const { splits, segments } = storage;
|
|
120
122
|
|
|
121
123
|
let startingUp = true;
|
|
122
124
|
|
|
@@ -133,53 +135,34 @@ export function splitChangesUpdaterFactory(
|
|
|
133
135
|
* @param noCache - true to revalidate data to fetch
|
|
134
136
|
* @param till - query param to bypass CDN requests
|
|
135
137
|
*/
|
|
136
|
-
return function splitChangesUpdater(noCache?: boolean, till?: number,
|
|
138
|
+
return function splitChangesUpdater(noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }) {
|
|
137
139
|
|
|
138
140
|
/**
|
|
139
141
|
* @param since - current changeNumber at splitsCache
|
|
140
142
|
* @param retry - current number of retry attempts
|
|
141
143
|
*/
|
|
142
|
-
function _splitChangesUpdater(
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
instantUpdate.type === SPLIT_UPDATE ?
|
|
148
|
-
// IFFU edge case: a change to a flag that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
|
|
149
|
-
Promise.resolve(rbSegments.contains(parseSegments(instantUpdate.payload, IN_RULE_BASED_SEGMENT))).then((contains) => {
|
|
150
|
-
return contains ?
|
|
151
|
-
{ ff: { d: [instantUpdate.payload as ISplit], t: instantUpdate.changeNumber } } :
|
|
152
|
-
splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
|
|
153
|
-
}) :
|
|
154
|
-
{ rbs: { d: [instantUpdate.payload as IRBSegment], t: instantUpdate.changeNumber } } :
|
|
155
|
-
splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator)
|
|
144
|
+
function _splitChangesUpdater(since: number, retry = 0): Promise<boolean> {
|
|
145
|
+
log.debug(SYNC_SPLITS_FETCH, [since]);
|
|
146
|
+
const fetcherPromise = Promise.resolve(splitUpdateNotification ?
|
|
147
|
+
{ splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
|
|
148
|
+
splitChangesFetcher(since, noCache, till, _promiseDecorator)
|
|
156
149
|
)
|
|
157
150
|
.then((splitChanges: ISplitChangesResponse) => {
|
|
158
151
|
startingUp = false;
|
|
159
152
|
|
|
160
|
-
const
|
|
153
|
+
const mutation = computeSplitsMutation(splitChanges.splits, splitFiltersValidation);
|
|
161
154
|
|
|
162
|
-
|
|
163
|
-
if (splitChanges.ff) {
|
|
164
|
-
const { added, removed } = computeMutation(splitChanges.ff.d, usedSegments, splitFiltersValidation);
|
|
165
|
-
log.debug(SYNC_SPLITS_UPDATE, [added.length, removed.length]);
|
|
166
|
-
ffUpdate = splits.update(added, removed, splitChanges.ff.t);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
let rbsUpdate: MaybeThenable<boolean> = false;
|
|
170
|
-
if (splitChanges.rbs) {
|
|
171
|
-
const { added, removed } = computeMutation(splitChanges.rbs.d, usedSegments);
|
|
172
|
-
log.debug(SYNC_RBS_UPDATE, [added.length, removed.length]);
|
|
173
|
-
rbsUpdate = rbSegments.update(added, removed, splitChanges.rbs.t);
|
|
174
|
-
}
|
|
155
|
+
log.debug(SYNC_SPLITS_UPDATE, [mutation.added.length, mutation.removed.length, mutation.segments.length]);
|
|
175
156
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
157
|
+
// Write into storage
|
|
158
|
+
// @TODO call `setChangeNumber` only if the other storage operations have succeeded, in order to keep storage consistency
|
|
159
|
+
return Promise.all([
|
|
160
|
+
splits.update(mutation.added, mutation.removed, splitChanges.till),
|
|
161
|
+
segments.registerSegments(mutation.segments)
|
|
162
|
+
]).then(([isThereUpdate]) => {
|
|
180
163
|
if (splitsEventEmitter) {
|
|
181
164
|
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
182
|
-
return Promise.resolve(!splitsEventEmitter.splitsArrived || (
|
|
165
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && isThereUpdate && (isClientSide || checkAllSegmentsExist(segments))))
|
|
183
166
|
.catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
184
167
|
.then(emitSplitsArrivedEvent => {
|
|
185
168
|
// emit SDK events
|
|
@@ -196,7 +179,7 @@ export function splitChangesUpdaterFactory(
|
|
|
196
179
|
if (startingUp && retriesOnFailureBeforeReady > retry) {
|
|
197
180
|
retry += 1;
|
|
198
181
|
log.info(SYNC_SPLITS_FETCH_RETRY, [retry, error]);
|
|
199
|
-
return _splitChangesUpdater(
|
|
182
|
+
return _splitChangesUpdater(since, retry);
|
|
200
183
|
} else {
|
|
201
184
|
startingUp = false;
|
|
202
185
|
}
|
|
@@ -213,7 +196,7 @@ export function splitChangesUpdaterFactory(
|
|
|
213
196
|
return fetcherPromise;
|
|
214
197
|
}
|
|
215
198
|
|
|
216
|
-
// `getChangeNumber` never rejects or throws error
|
|
217
|
-
return
|
|
199
|
+
let sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error
|
|
200
|
+
return sincePromise.then(_splitChangesUpdater);
|
|
218
201
|
};
|
|
219
202
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { errorParser, messageParser } from './NotificationParser';
|
|
2
2
|
import { notificationKeeperFactory } from './NotificationKeeper';
|
|
3
|
-
import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE
|
|
3
|
+
import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE } from '../constants';
|
|
4
4
|
import { IPushEventEmitter } from '../types';
|
|
5
5
|
import { ISseEventHandler } from '../SSEClient/types';
|
|
6
6
|
import { INotificationError, INotificationMessage } from './types';
|
|
@@ -84,7 +84,6 @@ export function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventEmitter,
|
|
|
84
84
|
case MEMBERSHIPS_MS_UPDATE:
|
|
85
85
|
case MEMBERSHIPS_LS_UPDATE:
|
|
86
86
|
case SPLIT_KILL:
|
|
87
|
-
case RB_SEGMENT_UPDATE:
|
|
88
87
|
pushEmitter.emit(parsedData.type, parsedData);
|
|
89
88
|
break;
|
|
90
89
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ControlType } from '../constants';
|
|
2
|
-
import { SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE
|
|
2
|
+
import { SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../types';
|
|
3
3
|
|
|
4
4
|
export enum Compression {
|
|
5
5
|
None = 0,
|
|
@@ -42,7 +42,7 @@ export interface ISegmentUpdateData {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
export interface ISplitUpdateData {
|
|
45
|
-
type: SPLIT_UPDATE
|
|
45
|
+
type: SPLIT_UPDATE,
|
|
46
46
|
changeNumber: number,
|
|
47
47
|
pcn?: number,
|
|
48
48
|
d?: string,
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { STREAMING_PARSING_SPLIT_UPDATE } from '../../../logger/constants';
|
|
1
|
+
import { ISplit } from '../../../dtos/types';
|
|
3
2
|
import { ILogger } from '../../../logger/types';
|
|
4
3
|
import { SDK_SPLITS_ARRIVED } from '../../../readiness/constants';
|
|
5
4
|
import { ISplitsEventEmitter } from '../../../readiness/types';
|
|
6
|
-
import {
|
|
5
|
+
import { ISplitsCacheSync } from '../../../storages/types';
|
|
7
6
|
import { ITelemetryTracker } from '../../../trackers/types';
|
|
8
7
|
import { Backoff } from '../../../utils/Backoff';
|
|
9
8
|
import { SPLITS } from '../../../utils/constants';
|
|
10
9
|
import { ISegmentsSyncTask, ISplitsSyncTask } from '../../polling/types';
|
|
11
|
-
import { InstantUpdate } from '../../polling/updaters/splitChangesUpdater';
|
|
12
|
-
import { RB_SEGMENT_UPDATE } from '../constants';
|
|
13
|
-
import { parseFFUpdatePayload } from '../parseUtils';
|
|
14
10
|
import { ISplitKillData, ISplitUpdateData } from '../SSEHandler/types';
|
|
15
11
|
import { FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT, FETCH_BACKOFF_MAX_RETRIES } from './constants';
|
|
16
12
|
import { IUpdateWorker } from './types';
|
|
@@ -18,128 +14,102 @@ import { IUpdateWorker } from './types';
|
|
|
18
14
|
/**
|
|
19
15
|
* SplitsUpdateWorker factory
|
|
20
16
|
*/
|
|
21
|
-
export function SplitsUpdateWorker(log: ILogger,
|
|
17
|
+
export function SplitsUpdateWorker(log: ILogger, splitsCache: ISplitsCacheSync, splitsSyncTask: ISplitsSyncTask, splitsEventEmitter: ISplitsEventEmitter, telemetryTracker: ITelemetryTracker, segmentsSyncTask?: ISegmentsSyncTask): IUpdateWorker<[updateData: ISplitUpdateData, payload?: ISplit]> & { killSplit(event: ISplitKillData): void } {
|
|
22
18
|
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
let maxChangeNumber = 0;
|
|
20
|
+
let handleNewEvent = false;
|
|
21
|
+
let isHandlingEvent: boolean;
|
|
22
|
+
let cdnBypass: boolean;
|
|
23
|
+
let payload: ISplit | undefined;
|
|
24
|
+
const backoff = new Backoff(__handleSplitUpdateCall, FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT);
|
|
25
25
|
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
function __handleSplitUpdateCall() {
|
|
27
|
+
isHandlingEvent = true;
|
|
28
|
+
if (maxChangeNumber > splitsCache.getChangeNumber()) {
|
|
29
|
+
handleNewEvent = false;
|
|
30
|
+
const splitUpdateNotification = payload ? { payload, changeNumber: maxChangeNumber } : undefined;
|
|
31
|
+
// fetch splits revalidating data if cached
|
|
32
|
+
splitsSyncTask.execute(true, cdnBypass ? maxChangeNumber : undefined, splitUpdateNotification).then(() => {
|
|
33
|
+
if (!isHandlingEvent) return; // halt if `stop` has been called
|
|
34
|
+
if (handleNewEvent) {
|
|
35
|
+
__handleSplitUpdateCall();
|
|
36
|
+
} else {
|
|
37
|
+
if (splitUpdateNotification) telemetryTracker.trackUpdatesFromSSE(SPLITS);
|
|
38
|
+
// fetch new registered segments for server-side API. Not retrying on error
|
|
39
|
+
if (segmentsSyncTask) segmentsSyncTask.execute(true);
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
isHandlingEvent = true;
|
|
36
|
-
if (maxChangeNumber > cache.getChangeNumber()) {
|
|
37
|
-
handleNewEvent = false;
|
|
38
|
-
// fetch splits revalidating data if cached
|
|
39
|
-
splitsSyncTask.execute(true, cdnBypass ? maxChangeNumber : undefined, instantUpdate).then(() => {
|
|
40
|
-
if (!isHandlingEvent) return; // halt if `stop` has been called
|
|
41
|
-
if (handleNewEvent) {
|
|
42
|
-
__handleSplitUpdateCall();
|
|
43
|
-
} else {
|
|
44
|
-
if (instantUpdate) telemetryTracker.trackUpdatesFromSSE(SPLITS);
|
|
45
|
-
// fetch new registered segments for server-side API. Not retrying on error
|
|
46
|
-
if (segmentsSyncTask) segmentsSyncTask.execute(true);
|
|
47
|
-
|
|
48
|
-
const attempts = backoff.attempts + 1;
|
|
41
|
+
const attempts = backoff.attempts + 1;
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
43
|
+
if (maxChangeNumber <= splitsCache.getChangeNumber()) {
|
|
44
|
+
log.debug(`Refresh completed${cdnBypass ? ' bypassing the CDN' : ''} in ${attempts} attempts.`);
|
|
45
|
+
isHandlingEvent = false;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
55
48
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
if (attempts < FETCH_BACKOFF_MAX_RETRIES) {
|
|
50
|
+
backoff.scheduleCall();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
60
53
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
54
|
+
if (cdnBypass) {
|
|
55
|
+
log.debug(`No changes fetched after ${attempts} attempts with CDN bypassed.`);
|
|
56
|
+
isHandlingEvent = false;
|
|
57
|
+
} else {
|
|
58
|
+
backoff.reset();
|
|
59
|
+
cdnBypass = true;
|
|
60
|
+
__handleSplitUpdateCall();
|
|
69
61
|
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
} else {
|
|
65
|
+
isHandlingEvent = false;
|
|
74
66
|
}
|
|
67
|
+
}
|
|
75
68
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const currentChangeNumber = cache.getChangeNumber();
|
|
69
|
+
/**
|
|
70
|
+
* Invoked by NotificationProcessor on SPLIT_UPDATE event
|
|
71
|
+
*
|
|
72
|
+
* @param changeNumber - change number of the SPLIT_UPDATE notification
|
|
73
|
+
*/
|
|
74
|
+
function put({ changeNumber, pcn }: ISplitUpdateData, _payload?: ISplit) {
|
|
75
|
+
const currentChangeNumber = splitsCache.getChangeNumber();
|
|
84
76
|
|
|
85
|
-
|
|
77
|
+
if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber) return;
|
|
86
78
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
79
|
+
maxChangeNumber = changeNumber;
|
|
80
|
+
handleNewEvent = true;
|
|
81
|
+
cdnBypass = false;
|
|
82
|
+
payload = undefined;
|
|
91
83
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
84
|
+
if (_payload && currentChangeNumber === pcn) {
|
|
85
|
+
payload = _payload;
|
|
86
|
+
}
|
|
95
87
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
stop() {
|
|
100
|
-
isHandlingEvent = false;
|
|
101
|
-
backoff.reset();
|
|
102
|
-
},
|
|
103
|
-
isSync() {
|
|
104
|
-
return maxChangeNumber <= cache.getChangeNumber();
|
|
105
|
-
}
|
|
106
|
-
};
|
|
88
|
+
if (backoff.timeoutID || !isHandlingEvent) __handleSplitUpdateCall();
|
|
89
|
+
backoff.reset();
|
|
107
90
|
}
|
|
108
91
|
|
|
109
92
|
return {
|
|
110
|
-
put
|
|
111
|
-
if (parsedData.d && parsedData.c !== undefined) {
|
|
112
|
-
try {
|
|
113
|
-
const payload = parseFFUpdatePayload(parsedData.c, parsedData.d);
|
|
114
|
-
if (payload) {
|
|
115
|
-
(parsedData.type === RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData, payload);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
} catch (e) {
|
|
119
|
-
log.warn(STREAMING_PARSING_SPLIT_UPDATE, [parsedData.type, e]);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
(parsedData.type === RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData);
|
|
123
|
-
},
|
|
93
|
+
put,
|
|
124
94
|
/**
|
|
125
95
|
* Invoked by NotificationProcessor on SPLIT_KILL event
|
|
126
96
|
*
|
|
127
|
-
* @param changeNumber - change number of the notification
|
|
97
|
+
* @param changeNumber - change number of the SPLIT_UPDATE notification
|
|
128
98
|
* @param splitName - name of split to kill
|
|
129
99
|
* @param defaultTreatment - default treatment value
|
|
130
100
|
*/
|
|
131
101
|
killSplit({ changeNumber, splitName, defaultTreatment }: ISplitKillData) {
|
|
132
|
-
if (
|
|
102
|
+
if (splitsCache.killLocally(splitName, defaultTreatment, changeNumber)) {
|
|
133
103
|
// trigger an SDK_UPDATE if Split was killed locally
|
|
134
104
|
splitsEventEmitter.emit(SDK_SPLITS_ARRIVED, true);
|
|
135
105
|
}
|
|
136
106
|
// queues the SplitChanges fetch (only if changeNumber is newer)
|
|
137
|
-
|
|
107
|
+
put({ changeNumber } as ISplitUpdateData);
|
|
138
108
|
},
|
|
139
109
|
|
|
140
110
|
stop() {
|
|
141
|
-
|
|
142
|
-
|
|
111
|
+
isHandlingEvent = false;
|
|
112
|
+
backoff.reset();
|
|
143
113
|
}
|
|
144
114
|
};
|
|
145
115
|
}
|
|
@@ -30,7 +30,6 @@ export const MEMBERSHIPS_LS_UPDATE = 'MEMBERSHIPS_LS_UPDATE';
|
|
|
30
30
|
export const SEGMENT_UPDATE = 'SEGMENT_UPDATE';
|
|
31
31
|
export const SPLIT_KILL = 'SPLIT_KILL';
|
|
32
32
|
export const SPLIT_UPDATE = 'SPLIT_UPDATE';
|
|
33
|
-
export const RB_SEGMENT_UPDATE = 'RB_SEGMENT_UPDATE';
|
|
34
33
|
|
|
35
34
|
// Control-type push notifications, handled by NotificationKeeper
|
|
36
35
|
export const CONTROL = 'CONTROL';
|
|
@@ -2,7 +2,7 @@ import { algorithms } from '../../utils/decompress';
|
|
|
2
2
|
import { decodeFromBase64 } from '../../utils/base64';
|
|
3
3
|
import { hash } from '../../utils/murmur3/murmur3';
|
|
4
4
|
import { Compression, IMembershipMSUpdateData, KeyList } from './SSEHandler/types';
|
|
5
|
-
import {
|
|
5
|
+
import { ISplit } from '../../dtos/types';
|
|
6
6
|
|
|
7
7
|
const GZIP = 1;
|
|
8
8
|
const ZLIB = 2;
|
|
@@ -82,7 +82,7 @@ export function isInBitmap(bitmap: Uint8Array, hash64hex: string) {
|
|
|
82
82
|
/**
|
|
83
83
|
* Parse feature flags notifications for instant feature flag updates
|
|
84
84
|
*/
|
|
85
|
-
export function parseFFUpdatePayload(compression: Compression, data: string): ISplit |
|
|
85
|
+
export function parseFFUpdatePayload(compression: Compression, data: string): ISplit | undefined {
|
|
86
86
|
return compression > 0 ?
|
|
87
87
|
parseKeyList(data, compression, false) :
|
|
88
88
|
JSON.parse(decodeFromBase64(data));
|
|
@@ -11,10 +11,10 @@ import { authenticateFactory, hashUserKey } from './AuthClient';
|
|
|
11
11
|
import { forOwn } from '../../utils/lang';
|
|
12
12
|
import { SSEClient } from './SSEClient';
|
|
13
13
|
import { getMatching } from '../../utils/key';
|
|
14
|
-
import { MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE,
|
|
15
|
-
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MEMBERSHIPS_UPDATE } from '../../logger/constants';
|
|
14
|
+
import { MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType } from './constants';
|
|
15
|
+
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MEMBERSHIPS_UPDATE, STREAMING_PARSING_SPLIT_UPDATE } from '../../logger/constants';
|
|
16
16
|
import { IMembershipMSUpdateData, IMembershipLSUpdateData, KeyList, UpdateStrategy } from './SSEHandler/types';
|
|
17
|
-
import { getDelay, isInBitmap, parseBitmap, parseKeyList } from './parseUtils';
|
|
17
|
+
import { getDelay, isInBitmap, parseBitmap, parseFFUpdatePayload, parseKeyList } from './parseUtils';
|
|
18
18
|
import { Hash64, hash64 } from '../../utils/murmur3/murmur3_64';
|
|
19
19
|
import { IAuthTokenPushEnabled } from './AuthClient/types';
|
|
20
20
|
import { TOKEN_REFRESH, AUTH_REJECTION } from '../../utils/constants';
|
|
@@ -56,7 +56,7 @@ export function pushManagerFactory(
|
|
|
56
56
|
// MySegmentsUpdateWorker (client-side) are initiated in `add` method
|
|
57
57
|
const segmentsUpdateWorker = userKey ? undefined : SegmentsUpdateWorker(log, pollingManager.segmentsSyncTask as ISegmentsSyncTask, storage.segments);
|
|
58
58
|
// For server-side we pass the segmentsSyncTask, used by SplitsUpdateWorker to fetch new segments
|
|
59
|
-
const splitsUpdateWorker = SplitsUpdateWorker(log, storage, pollingManager.splitsSyncTask, readiness.splits, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask as ISegmentsSyncTask);
|
|
59
|
+
const splitsUpdateWorker = SplitsUpdateWorker(log, storage.splits, pollingManager.splitsSyncTask, readiness.splits, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask as ISegmentsSyncTask);
|
|
60
60
|
|
|
61
61
|
// [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
|
|
62
62
|
const userKeyHashes: Record<string, string> = {};
|
|
@@ -219,8 +219,20 @@ export function pushManagerFactory(
|
|
|
219
219
|
/** Functions related to synchronization (Queues and Workers in the spec) */
|
|
220
220
|
|
|
221
221
|
pushEmitter.on(SPLIT_KILL, splitsUpdateWorker.killSplit);
|
|
222
|
-
pushEmitter.on(SPLIT_UPDATE,
|
|
223
|
-
|
|
222
|
+
pushEmitter.on(SPLIT_UPDATE, (parsedData) => {
|
|
223
|
+
if (parsedData.d && parsedData.c !== undefined) {
|
|
224
|
+
try {
|
|
225
|
+
const payload = parseFFUpdatePayload(parsedData.c, parsedData.d);
|
|
226
|
+
if (payload) {
|
|
227
|
+
splitsUpdateWorker.put(parsedData, payload);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
} catch (e) {
|
|
231
|
+
log.warn(STREAMING_PARSING_SPLIT_UPDATE, [e]);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
splitsUpdateWorker.put(parsedData);
|
|
235
|
+
});
|
|
224
236
|
|
|
225
237
|
function handleMySegmentsUpdate(parsedData: IMembershipMSUpdateData | IMembershipLSUpdateData) {
|
|
226
238
|
switch (parsedData.u) {
|
|
@@ -16,19 +16,18 @@ export type MEMBERSHIPS_LS_UPDATE = 'MEMBERSHIPS_LS_UPDATE';
|
|
|
16
16
|
export type SEGMENT_UPDATE = 'SEGMENT_UPDATE';
|
|
17
17
|
export type SPLIT_KILL = 'SPLIT_KILL';
|
|
18
18
|
export type SPLIT_UPDATE = 'SPLIT_UPDATE';
|
|
19
|
-
export type RB_SEGMENT_UPDATE = 'RB_SEGMENT_UPDATE';
|
|
20
19
|
|
|
21
20
|
// Control-type push notifications, handled by NotificationKeeper
|
|
22
21
|
export type CONTROL = 'CONTROL';
|
|
23
22
|
export type OCCUPANCY = 'OCCUPANCY';
|
|
24
23
|
|
|
25
|
-
export type IPushEvent = PUSH_SUBSYSTEM_UP | PUSH_SUBSYSTEM_DOWN | PUSH_NONRETRYABLE_ERROR | PUSH_RETRYABLE_ERROR | MEMBERSHIPS_MS_UPDATE | MEMBERSHIPS_LS_UPDATE | SEGMENT_UPDATE | SPLIT_UPDATE | SPLIT_KILL |
|
|
24
|
+
export type IPushEvent = PUSH_SUBSYSTEM_UP | PUSH_SUBSYSTEM_DOWN | PUSH_NONRETRYABLE_ERROR | PUSH_RETRYABLE_ERROR | MEMBERSHIPS_MS_UPDATE | MEMBERSHIPS_LS_UPDATE | SEGMENT_UPDATE | SPLIT_UPDATE | SPLIT_KILL | ControlType.STREAMING_RESET
|
|
26
25
|
|
|
27
26
|
type IParsedData<T extends IPushEvent> =
|
|
28
27
|
T extends MEMBERSHIPS_MS_UPDATE ? IMembershipMSUpdateData :
|
|
29
28
|
T extends MEMBERSHIPS_LS_UPDATE ? IMembershipLSUpdateData :
|
|
30
29
|
T extends SEGMENT_UPDATE ? ISegmentUpdateData :
|
|
31
|
-
T extends SPLIT_UPDATE
|
|
30
|
+
T extends SPLIT_UPDATE ? ISplitUpdateData :
|
|
32
31
|
T extends SPLIT_KILL ? ISplitKillData : INotificationData;
|
|
33
32
|
|
|
34
33
|
/**
|
|
@@ -25,8 +25,9 @@ export function fromImpressionsCollector(sendLabels: boolean, data: SplitIO.Impr
|
|
|
25
25
|
m: entry.time, // Timestamp
|
|
26
26
|
c: entry.changeNumber, // ChangeNumber
|
|
27
27
|
r: sendLabels ? entry.label : undefined, // Rule
|
|
28
|
-
b: entry.bucketingKey
|
|
29
|
-
pt: entry.pt
|
|
28
|
+
b: entry.bucketingKey, // Bucketing Key
|
|
29
|
+
pt: entry.pt, // Previous time
|
|
30
|
+
properties: entry.properties // Properties
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
return keyImpression;
|
|
@@ -3,26 +3,30 @@ import { IMetadata } from '../../dtos/types';
|
|
|
3
3
|
import SplitIO from '../../../types/splitio';
|
|
4
4
|
import { ISyncTask } from '../types';
|
|
5
5
|
|
|
6
|
+
type ImpressionPayload = {
|
|
7
|
+
/** Matching Key */
|
|
8
|
+
k: string;
|
|
9
|
+
/** Bucketing Key */
|
|
10
|
+
b?: string;
|
|
11
|
+
/** Treatment */
|
|
12
|
+
t: string;
|
|
13
|
+
/** Timestamp */
|
|
14
|
+
m: number;
|
|
15
|
+
/** Change number */
|
|
16
|
+
c: number;
|
|
17
|
+
/** Rule label */
|
|
18
|
+
r?: string;
|
|
19
|
+
/** Previous time */
|
|
20
|
+
pt?: number;
|
|
21
|
+
/** Stringified JSON object with properties */
|
|
22
|
+
properties?: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
6
25
|
export type ImpressionsPayload = {
|
|
7
26
|
/** Split name */
|
|
8
27
|
f: string,
|
|
9
28
|
/** Key Impressions */
|
|
10
|
-
i:
|
|
11
|
-
/** User Key */
|
|
12
|
-
k: string;
|
|
13
|
-
/** Treatment */
|
|
14
|
-
t: string;
|
|
15
|
-
/** Timestamp */
|
|
16
|
-
m: number;
|
|
17
|
-
/** ChangeNumber */
|
|
18
|
-
c: number;
|
|
19
|
-
/** Rule label */
|
|
20
|
-
r?: string;
|
|
21
|
-
/** Bucketing Key */
|
|
22
|
-
b?: string;
|
|
23
|
-
/** Previous time */
|
|
24
|
-
pt?: number;
|
|
25
|
-
}[]
|
|
29
|
+
i: ImpressionPayload[]
|
|
26
30
|
}[]
|
|
27
31
|
|
|
28
32
|
export type ImpressionCountsPayload = {
|
|
@@ -60,23 +64,9 @@ export type StoredImpressionWithMetadata = {
|
|
|
60
64
|
/** Metadata */
|
|
61
65
|
m: IMetadata,
|
|
62
66
|
/** Stored impression */
|
|
63
|
-
i: {
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
/** bucketingKey */
|
|
67
|
-
b?: string,
|
|
68
|
-
/** Split name */
|
|
69
|
-
f: string,
|
|
70
|
-
/** treatment */
|
|
71
|
-
t: string,
|
|
72
|
-
/** label */
|
|
73
|
-
r: string,
|
|
74
|
-
/** changeNumber */
|
|
75
|
-
c: number,
|
|
76
|
-
/** time */
|
|
77
|
-
m: number
|
|
78
|
-
/** previous time */
|
|
79
|
-
pt?: number
|
|
67
|
+
i: ImpressionPayload & {
|
|
68
|
+
/** Feature flag name */
|
|
69
|
+
f: string
|
|
80
70
|
}
|
|
81
71
|
}
|
|
82
72
|
|
|
@@ -149,14 +149,14 @@ export function syncManagerOnlineFactory(
|
|
|
149
149
|
if (pushManager) {
|
|
150
150
|
if (pollingManager.isRunning()) {
|
|
151
151
|
// if doing polling, we must start the periodic fetch of data
|
|
152
|
-
if (storage.splits.usesSegments()
|
|
152
|
+
if (storage.splits.usesSegments()) mySegmentsSyncTask.start();
|
|
153
153
|
} else {
|
|
154
154
|
// if not polling, we must execute the sync task for the initial fetch
|
|
155
155
|
// of segments since `syncAll` was already executed when starting the main client
|
|
156
156
|
mySegmentsSyncTask.execute();
|
|
157
157
|
}
|
|
158
158
|
} else {
|
|
159
|
-
if (storage.splits.usesSegments()
|
|
159
|
+
if (storage.splits.usesSegments()) mySegmentsSyncTask.start();
|
|
160
160
|
}
|
|
161
161
|
} else {
|
|
162
162
|
if (!readinessManager.isReady()) mySegmentsSyncTask.execute();
|