@splitsoftware/splitio-commons 1.16.0 → 1.16.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/cjs/evaluator/matchers/index.js +3 -1
- package/cjs/evaluator/matchers/large_segment.js +16 -0
- package/cjs/evaluator/matchers/matcherTypes.js +1 -0
- package/cjs/evaluator/matchersTransform/index.js +1 -1
- package/cjs/logger/constants.js +4 -4
- package/cjs/logger/messages/info.js +0 -1
- package/cjs/readiness/readinessManager.js +14 -10
- package/cjs/readiness/sdkReadinessManager.js +5 -6
- package/cjs/sdkClient/sdkClientMethodCS.js +3 -4
- package/cjs/sdkClient/sdkClientMethodCSWithTT.js +4 -5
- package/cjs/sdkFactory/index.js +1 -1
- package/cjs/services/splitApi.js +4 -0
- package/cjs/storages/AbstractSplitsCacheAsync.js +2 -2
- package/cjs/storages/AbstractSplitsCacheSync.js +5 -5
- package/cjs/storages/KeyBuilder.js +3 -0
- package/cjs/storages/KeyBuilderCS.js +17 -5
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +16 -4
- package/cjs/storages/inLocalStorage/index.js +6 -2
- package/cjs/storages/inMemory/InMemoryStorageCS.js +5 -0
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +20 -11
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +7 -10
- package/cjs/storages/pluggable/inMemoryWrapper.js +1 -1
- package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +5 -1
- package/cjs/sync/polling/pollingManagerCS.js +51 -33
- package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +5 -6
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +2 -1
- package/cjs/sync/streaming/SSEHandler/index.js +1 -0
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +15 -5
- package/cjs/sync/streaming/constants.js +2 -1
- package/cjs/sync/streaming/pushManager.js +95 -64
- package/cjs/sync/submitters/telemetrySubmitter.js +2 -0
- package/cjs/sync/syncManagerOnline.js +24 -14
- package/cjs/utils/constants/index.js +5 -1
- package/cjs/utils/settingsValidation/index.js +9 -4
- package/esm/evaluator/matchers/index.js +3 -1
- package/esm/evaluator/matchers/large_segment.js +12 -0
- package/esm/evaluator/matchers/matcherTypes.js +1 -0
- package/esm/evaluator/matchersTransform/index.js +1 -1
- package/esm/logger/constants.js +1 -1
- package/esm/logger/messages/info.js +0 -1
- package/esm/readiness/readinessManager.js +14 -10
- package/esm/readiness/sdkReadinessManager.js +5 -6
- package/esm/sdkClient/sdkClientMethodCS.js +4 -5
- package/esm/sdkClient/sdkClientMethodCSWithTT.js +5 -6
- package/esm/sdkFactory/index.js +1 -1
- package/esm/services/splitApi.js +5 -1
- package/esm/storages/AbstractSplitsCacheAsync.js +2 -2
- package/esm/storages/AbstractSplitsCacheSync.js +3 -3
- package/esm/storages/KeyBuilder.js +3 -0
- package/esm/storages/KeyBuilderCS.js +15 -4
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +17 -5
- package/esm/storages/inLocalStorage/index.js +7 -3
- package/esm/storages/inMemory/InMemoryStorageCS.js +5 -0
- package/esm/storages/inMemory/SplitsCacheInMemory.js +21 -12
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +7 -10
- package/esm/storages/pluggable/inMemoryWrapper.js +1 -1
- package/esm/sync/polling/fetchers/mySegmentsFetcher.js +5 -1
- package/esm/sync/polling/pollingManagerCS.js +52 -34
- package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +3 -4
- package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -1
- package/esm/sync/streaming/SSEHandler/index.js +2 -1
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +15 -5
- package/esm/sync/streaming/constants.js +1 -0
- package/esm/sync/streaming/pushManager.js +95 -65
- package/esm/sync/submitters/telemetrySubmitter.js +2 -0
- package/esm/sync/syncManagerOnline.js +25 -15
- package/esm/utils/constants/index.js +4 -0
- package/esm/utils/settingsValidation/index.js +10 -5
- package/package.json +1 -1
- package/src/dtos/types.ts +17 -7
- package/src/evaluator/matchers/index.ts +2 -0
- package/src/evaluator/matchers/large_segment.ts +18 -0
- package/src/evaluator/matchers/matcherTypes.ts +1 -0
- package/src/evaluator/matchersTransform/index.ts +1 -1
- package/src/logger/constants.ts +1 -1
- package/src/logger/messages/info.ts +0 -1
- package/src/readiness/readinessManager.ts +13 -9
- package/src/readiness/sdkReadinessManager.ts +7 -7
- package/src/readiness/types.ts +3 -2
- package/src/sdkClient/sdkClientMethodCS.ts +4 -6
- package/src/sdkClient/sdkClientMethodCSWithTT.ts +5 -7
- package/src/sdkFactory/index.ts +1 -1
- package/src/services/splitApi.ts +6 -1
- package/src/services/types.ts +1 -0
- package/src/storages/AbstractSplitsCacheAsync.ts +2 -2
- package/src/storages/AbstractSplitsCacheSync.ts +4 -4
- package/src/storages/KeyBuilder.ts +3 -0
- package/src/storages/KeyBuilderCS.ts +25 -5
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +3 -3
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +20 -5
- package/src/storages/inLocalStorage/index.ts +8 -4
- package/src/storages/inMemory/InMemoryStorageCS.ts +5 -0
- package/src/storages/inMemory/SplitsCacheInMemory.ts +15 -10
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +7 -11
- package/src/storages/pluggable/inMemoryWrapper.ts +1 -1
- package/src/storages/types.ts +7 -5
- package/src/sync/polling/fetchers/mySegmentsFetcher.ts +6 -2
- package/src/sync/polling/pollingManagerCS.ts +61 -29
- package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +10 -10
- package/src/sync/polling/types.ts +3 -2
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +5 -8
- package/src/sync/polling/updaters/splitChangesUpdater.ts +4 -3
- package/src/sync/streaming/SSEHandler/index.ts +2 -1
- package/src/sync/streaming/SSEHandler/types.ts +14 -2
- package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +17 -5
- package/src/sync/streaming/constants.ts +1 -0
- package/src/sync/streaming/pushManager.ts +100 -63
- package/src/sync/streaming/types.ts +5 -3
- package/src/sync/submitters/telemetrySubmitter.ts +2 -0
- package/src/sync/submitters/types.ts +10 -4
- package/src/sync/syncManagerOnline.ts +19 -11
- package/src/types.ts +26 -1
- package/src/utils/constants/index.ts +5 -0
- package/src/utils/settingsValidation/index.ts +11 -6
- package/src/utils/settingsValidation/types.ts +1 -1
- package/types/dtos/types.d.ts +14 -6
- package/types/evaluator/matchers/large_segment.d.ts +5 -0
- package/types/logger/constants.d.ts +1 -1
- package/types/readiness/readinessManager.d.ts +2 -2
- package/types/readiness/sdkReadinessManager.d.ts +2 -3
- package/types/readiness/types.d.ts +3 -2
- package/types/services/types.d.ts +1 -0
- package/types/storages/AbstractSplitsCacheAsync.d.ts +1 -1
- package/types/storages/AbstractSplitsCacheSync.d.ts +3 -3
- package/types/storages/KeyBuilder.d.ts +1 -0
- package/types/storages/KeyBuilderCS.d.ts +7 -2
- package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +2 -2
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +1 -1
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +3 -2
- package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +4 -6
- package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -1
- package/types/storages/types.d.ts +4 -3
- package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +2 -3
- package/types/sync/polling/types.d.ts +9 -2
- package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +4 -4
- package/types/sync/streaming/SSEHandler/types.d.ts +13 -2
- package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -1
- package/types/sync/streaming/constants.d.ts +1 -0
- package/types/sync/streaming/pushManager.d.ts +2 -0
- package/types/sync/streaming/types.d.ts +5 -4
- package/types/sync/submitters/types.d.ts +9 -3
- package/types/types.d.ts +25 -0
- package/types/utils/constants/index.d.ts +3 -0
- package/types/utils/settingsValidation/index.d.ts +2 -0
- package/types/utils/settingsValidation/types.d.ts +1 -1
|
@@ -6,8 +6,9 @@ import { mySegmentsSyncTaskFactory } from './syncTasks/mySegmentsSyncTask';
|
|
|
6
6
|
import { splitsSyncTaskFactory } from './syncTasks/splitsSyncTask';
|
|
7
7
|
import { getMatching } from '../../utils/key';
|
|
8
8
|
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../../readiness/constants';
|
|
9
|
-
import {
|
|
9
|
+
import { POLLING_START, POLLING_STOP } from '../../logger/constants';
|
|
10
10
|
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
11
|
+
import { IN_LARGE_SEGMENT, IN_SEGMENT } from '../../utils/constants';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Expose start / stop mechanism for polling data from services.
|
|
@@ -22,62 +23,92 @@ export function pollingManagerCSFactory(
|
|
|
22
23
|
|
|
23
24
|
const splitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings, true);
|
|
24
25
|
|
|
25
|
-
// Map of matching keys to their corresponding MySegmentsSyncTask.
|
|
26
|
-
const mySegmentsSyncTasks: Record<string, IMySegmentsSyncTask> = {};
|
|
26
|
+
// Map of matching keys to their corresponding MySegmentsSyncTask for segments and large segments.
|
|
27
|
+
const mySegmentsSyncTasks: Record<string, { msSyncTask: IMySegmentsSyncTask, mlsSyncTask?: IMySegmentsSyncTask }> = {};
|
|
27
28
|
|
|
28
29
|
const matchingKey = getMatching(settings.core.key);
|
|
29
|
-
const
|
|
30
|
+
const { msSyncTask, mlsSyncTask } = add(matchingKey, readiness, storage);
|
|
30
31
|
|
|
31
32
|
function startMySegmentsSyncTasks() {
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
const splitsHaveSegments = storage.splits.usesMatcher(IN_SEGMENT);
|
|
34
|
+
const splitsHaveLargeSegments = storage.splits.usesMatcher(IN_LARGE_SEGMENT);
|
|
35
|
+
|
|
36
|
+
forOwn(mySegmentsSyncTasks, ({ msSyncTask, mlsSyncTask }) => {
|
|
37
|
+
if (splitsHaveSegments) msSyncTask.start();
|
|
38
|
+
else msSyncTask.stop(); // smart pausing
|
|
39
|
+
|
|
40
|
+
if (mlsSyncTask) {
|
|
41
|
+
if (splitsHaveLargeSegments) mlsSyncTask.start();
|
|
42
|
+
else mlsSyncTask.stop(); // smart pausing
|
|
43
|
+
}
|
|
34
44
|
});
|
|
35
45
|
}
|
|
36
46
|
|
|
37
47
|
function stopMySegmentsSyncTasks() {
|
|
38
|
-
forOwn(mySegmentsSyncTasks,
|
|
39
|
-
|
|
48
|
+
forOwn(mySegmentsSyncTasks, ({ msSyncTask, mlsSyncTask }) => {
|
|
49
|
+
msSyncTask.stop();
|
|
50
|
+
mlsSyncTask && mlsSyncTask.stop();
|
|
40
51
|
});
|
|
41
52
|
}
|
|
42
53
|
|
|
43
|
-
// smart pausing
|
|
44
54
|
readiness.splits.on(SDK_SPLITS_ARRIVED, () => {
|
|
45
|
-
if (
|
|
46
|
-
const splitsHaveSegments = storage.splits.usesSegments();
|
|
47
|
-
if (splitsHaveSegments !== mySegmentsSyncTask.isRunning()) {
|
|
48
|
-
log.info(POLLING_SMART_PAUSING, [splitsHaveSegments ? 'ON' : 'OFF']);
|
|
49
|
-
if (splitsHaveSegments) {
|
|
50
|
-
startMySegmentsSyncTasks();
|
|
51
|
-
} else {
|
|
52
|
-
stopMySegmentsSyncTasks();
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
+
if (splitsSyncTask.isRunning()) startMySegmentsSyncTasks();
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
function add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync) {
|
|
58
|
-
const
|
|
59
|
+
const msSyncTask = mySegmentsSyncTaskFactory(
|
|
60
|
+
splitApi.fetchMySegments,
|
|
61
|
+
storage.segments,
|
|
62
|
+
() => { if (storage.splits.usesMatcher(IN_SEGMENT)) readiness.segments.emit(SDK_SEGMENTS_ARRIVED); },
|
|
63
|
+
settings,
|
|
64
|
+
matchingKey,
|
|
65
|
+
settings.scheduler.segmentsRefreshRate,
|
|
66
|
+
'mySegmentsUpdater'
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
let mlsSyncTask;
|
|
70
|
+
if (settings.sync.largeSegmentsEnabled) {
|
|
71
|
+
mlsSyncTask = mySegmentsSyncTaskFactory(
|
|
72
|
+
splitApi.fetchMyLargeSegments,
|
|
73
|
+
storage.largeSegments!,
|
|
74
|
+
() => { if (readiness.largeSegments && storage.splits.usesMatcher(IN_LARGE_SEGMENT)) readiness.largeSegments.emit(SDK_SEGMENTS_ARRIVED); },
|
|
75
|
+
settings,
|
|
76
|
+
matchingKey,
|
|
77
|
+
settings.scheduler.largeSegmentsRefreshRate,
|
|
78
|
+
'myLargeSegmentsUpdater'
|
|
79
|
+
);
|
|
80
|
+
}
|
|
59
81
|
|
|
60
82
|
// smart ready
|
|
61
83
|
function smartReady() {
|
|
62
|
-
if (!readiness.isReady()
|
|
84
|
+
if (!readiness.isReady()) {
|
|
85
|
+
if (readiness.largeSegments && !storage.splits.usesMatcher(IN_LARGE_SEGMENT)) readiness.largeSegments.emit(SDK_SEGMENTS_ARRIVED);
|
|
86
|
+
if (!storage.splits.usesMatcher(IN_SEGMENT)) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
87
|
+
}
|
|
63
88
|
}
|
|
64
|
-
if (!storage.splits.usesSegments()) setTimeout(smartReady, 0);
|
|
65
|
-
else readiness.splits.once(SDK_SPLITS_ARRIVED, smartReady);
|
|
66
89
|
|
|
67
|
-
|
|
68
|
-
|
|
90
|
+
if (storage.splits.usesMatcher(IN_SEGMENT) && storage.splits.usesMatcher(IN_LARGE_SEGMENT)) readiness.splits.once(SDK_SPLITS_ARRIVED, smartReady);
|
|
91
|
+
else setTimeout(smartReady, 0);
|
|
92
|
+
|
|
93
|
+
mySegmentsSyncTasks[matchingKey] = { msSyncTask: msSyncTask, mlsSyncTask: mlsSyncTask };
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
msSyncTask,
|
|
97
|
+
mlsSyncTask
|
|
98
|
+
};
|
|
69
99
|
}
|
|
70
100
|
|
|
71
101
|
return {
|
|
72
102
|
splitsSyncTask,
|
|
73
|
-
segmentsSyncTask:
|
|
103
|
+
segmentsSyncTask: msSyncTask,
|
|
104
|
+
largeSegmentsSyncTask: mlsSyncTask,
|
|
74
105
|
|
|
75
106
|
// Start periodic fetching (polling)
|
|
76
107
|
start() {
|
|
77
108
|
log.info(POLLING_START);
|
|
78
109
|
|
|
79
110
|
splitsSyncTask.start();
|
|
80
|
-
|
|
111
|
+
startMySegmentsSyncTasks();
|
|
81
112
|
},
|
|
82
113
|
|
|
83
114
|
// Stop periodic fetching (polling)
|
|
@@ -94,8 +125,9 @@ export function pollingManagerCSFactory(
|
|
|
94
125
|
// fetch splits and segments
|
|
95
126
|
syncAll() {
|
|
96
127
|
const promises = [splitsSyncTask.execute()];
|
|
97
|
-
forOwn(mySegmentsSyncTasks, function (
|
|
98
|
-
promises.push(
|
|
128
|
+
forOwn(mySegmentsSyncTasks, function ({ msSyncTask, mlsSyncTask }) {
|
|
129
|
+
promises.push(msSyncTask.execute());
|
|
130
|
+
mlsSyncTask && promises.push(mlsSyncTask.execute());
|
|
99
131
|
});
|
|
100
132
|
return Promise.all(promises);
|
|
101
133
|
},
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { IReadinessManager } from '../../../readiness/types';
|
|
1
|
+
import { ISegmentsCacheSync } from '../../../storages/types';
|
|
3
2
|
import { syncTaskFactory } from '../../syncTask';
|
|
4
3
|
import { IMySegmentsSyncTask } from '../types';
|
|
5
4
|
import { IFetchMySegments } from '../../../services/types';
|
|
@@ -12,24 +11,25 @@ import { mySegmentsUpdaterFactory } from '../updaters/mySegmentsUpdater';
|
|
|
12
11
|
*/
|
|
13
12
|
export function mySegmentsSyncTaskFactory(
|
|
14
13
|
fetchMySegments: IFetchMySegments,
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
mySegmentsCache: ISegmentsCacheSync,
|
|
15
|
+
notifyUpdate: () => void,
|
|
17
16
|
settings: ISettings,
|
|
18
|
-
matchingKey: string
|
|
17
|
+
matchingKey: string,
|
|
18
|
+
segmentsRefreshRate: number,
|
|
19
|
+
NAME: string
|
|
19
20
|
): IMySegmentsSyncTask {
|
|
20
21
|
return syncTaskFactory(
|
|
21
22
|
settings.log,
|
|
22
23
|
mySegmentsUpdaterFactory(
|
|
23
24
|
settings.log,
|
|
24
25
|
mySegmentsFetcherFactory(fetchMySegments),
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
readiness.segments,
|
|
26
|
+
mySegmentsCache,
|
|
27
|
+
notifyUpdate,
|
|
28
28
|
settings.startup.requestTimeoutBeforeReady,
|
|
29
29
|
settings.startup.retriesOnFailureBeforeReady,
|
|
30
30
|
matchingKey
|
|
31
31
|
),
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
segmentsRefreshRate,
|
|
33
|
+
NAME,
|
|
34
34
|
);
|
|
35
35
|
}
|
|
@@ -20,13 +20,14 @@ export interface IPollingManager extends ITask {
|
|
|
20
20
|
syncAll(): Promise<any>
|
|
21
21
|
splitsSyncTask: ISplitsSyncTask
|
|
22
22
|
segmentsSyncTask: ISyncTask
|
|
23
|
+
largeSegmentsSyncTask?: ISyncTask
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* PollingManager for client-side with support for multiple clients
|
|
27
28
|
*/
|
|
28
29
|
export interface IPollingManagerCS extends IPollingManager {
|
|
29
|
-
add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync): IMySegmentsSyncTask
|
|
30
|
+
add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync): { msSyncTask: IMySegmentsSyncTask, mlsSyncTask?: IMySegmentsSyncTask }
|
|
30
31
|
remove(matchingKey: string): void;
|
|
31
|
-
get(matchingKey: string): IMySegmentsSyncTask | undefined
|
|
32
|
+
get(matchingKey: string): { msSyncTask: IMySegmentsSyncTask, mlsSyncTask?: IMySegmentsSyncTask } | undefined
|
|
32
33
|
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { IMySegmentsFetcher } from '../fetchers/types';
|
|
2
|
-
import { ISegmentsCacheSync
|
|
3
|
-
import { ISegmentsEventEmitter } from '../../../readiness/types';
|
|
2
|
+
import { ISegmentsCacheSync } from '../../../storages/types';
|
|
4
3
|
import { timeout } from '../../../utils/promise/timeout';
|
|
5
|
-
import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
|
|
6
4
|
import { ILogger } from '../../../logger/types';
|
|
7
5
|
import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants';
|
|
8
6
|
import { MySegmentsData } from '../types';
|
|
9
7
|
|
|
10
|
-
type IMySegmentsUpdater = (segmentList?:
|
|
8
|
+
type IMySegmentsUpdater = (segmentList?: MySegmentsData, noCache?: boolean) => Promise<boolean>
|
|
11
9
|
|
|
12
10
|
/**
|
|
13
11
|
* factory of MySegments updater, a task that:
|
|
@@ -18,9 +16,8 @@ type IMySegmentsUpdater = (segmentList?: string[], noCache?: boolean) => Promise
|
|
|
18
16
|
export function mySegmentsUpdaterFactory(
|
|
19
17
|
log: ILogger,
|
|
20
18
|
mySegmentsFetcher: IMySegmentsFetcher,
|
|
21
|
-
splitsCache: ISplitsCacheSync,
|
|
22
19
|
mySegmentsCache: ISegmentsCacheSync,
|
|
23
|
-
|
|
20
|
+
notifyUpdate: () => void,
|
|
24
21
|
requestTimeoutBeforeReady: number,
|
|
25
22
|
retriesOnFailureBeforeReady: number,
|
|
26
23
|
matchingKey: string
|
|
@@ -55,9 +52,9 @@ export function mySegmentsUpdaterFactory(
|
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
// Notify update if required
|
|
58
|
-
if (
|
|
55
|
+
if (shouldNotifyUpdate || readyOnAlreadyExistentState) {
|
|
59
56
|
readyOnAlreadyExistentState = false;
|
|
60
|
-
|
|
57
|
+
notifyUpdate();
|
|
61
58
|
}
|
|
62
59
|
}
|
|
63
60
|
|
|
@@ -8,6 +8,7 @@ import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/
|
|
|
8
8
|
import { ILogger } from '../../../logger/types';
|
|
9
9
|
import { SYNC_SPLITS_FETCH, SYNC_SPLITS_NEW, SYNC_SPLITS_REMOVED, SYNC_SPLITS_SEGMENTS, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
|
|
10
10
|
import { startsWith } from '../../../utils/lang';
|
|
11
|
+
import { IN_SEGMENT } from '../../../utils/constants';
|
|
11
12
|
|
|
12
13
|
type ISplitChangesUpdater = (noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }) => Promise<boolean>
|
|
13
14
|
|
|
@@ -33,7 +34,7 @@ export function parseSegments({ conditions }: ISplit): ISet<string> {
|
|
|
33
34
|
const matchers = conditions[i].matcherGroup.matchers;
|
|
34
35
|
|
|
35
36
|
matchers.forEach(matcher => {
|
|
36
|
-
if (matcher.matcherType ===
|
|
37
|
+
if (matcher.matcherType === IN_SEGMENT) segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
|
|
37
38
|
});
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -54,7 +55,7 @@ interface ISplitMutations {
|
|
|
54
55
|
* @param filters splitFiltersValidation bySet | byName
|
|
55
56
|
*/
|
|
56
57
|
function matchFilters(featureFlag: ISplit, filters: ISplitFiltersValidation) {
|
|
57
|
-
const { bySet: setsFilter, byName: namesFilter, byPrefix: prefixFilter} = filters.groupedFilters;
|
|
58
|
+
const { bySet: setsFilter, byName: namesFilter, byPrefix: prefixFilter } = filters.groupedFilters;
|
|
58
59
|
if (setsFilter.length > 0) return featureFlag.sets && featureFlag.sets.some((featureFlagSet: string) => setsFilter.indexOf(featureFlagSet) > -1);
|
|
59
60
|
|
|
60
61
|
const namesFilterConfigured = namesFilter.length > 0;
|
|
@@ -129,7 +130,7 @@ export function splitChangesUpdaterFactory(
|
|
|
129
130
|
|
|
130
131
|
/** Returns true if at least one split was updated */
|
|
131
132
|
function isThereUpdate(flagsChange: [boolean | void, void | boolean[], void | boolean[], boolean | void] | [any, any, any]) {
|
|
132
|
-
const [, added, removed
|
|
133
|
+
const [, added, removed] = flagsChange;
|
|
133
134
|
// There is at least one added or modified feature flag
|
|
134
135
|
if (added && added.some((update: boolean) => update)) return true;
|
|
135
136
|
// There is at least one removed feature flag
|
|
@@ -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, MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE } from '../constants';
|
|
3
|
+
import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MY_LARGE_SEGMENTS_UPDATE } from '../constants';
|
|
4
4
|
import { IPushEventEmitter } from '../types';
|
|
5
5
|
import { ISseEventHandler } from '../SSEClient/types';
|
|
6
6
|
import { INotificationError, INotificationMessage } from './types';
|
|
@@ -83,6 +83,7 @@ export function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventEmitter,
|
|
|
83
83
|
case SPLIT_UPDATE:
|
|
84
84
|
case SEGMENT_UPDATE:
|
|
85
85
|
case MY_SEGMENTS_UPDATE_V2:
|
|
86
|
+
case MY_LARGE_SEGMENTS_UPDATE:
|
|
86
87
|
case SPLIT_KILL:
|
|
87
88
|
pushEmitter.emit(parsedData.type, parsedData);
|
|
88
89
|
break;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ControlType } from '../constants';
|
|
2
|
-
import { MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY } from '../types';
|
|
2
|
+
import { MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MY_LARGE_SEGMENTS_UPDATE } from '../types';
|
|
3
3
|
|
|
4
4
|
export interface IMySegmentsUpdateData {
|
|
5
5
|
type: MY_SEGMENTS_UPDATE,
|
|
@@ -35,6 +35,18 @@ export interface IMySegmentsUpdateV2Data {
|
|
|
35
35
|
u: UpdateStrategy,
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export interface IMyLargeSegmentsUpdateData {
|
|
39
|
+
type: MY_LARGE_SEGMENTS_UPDATE,
|
|
40
|
+
changeNumber: number,
|
|
41
|
+
largeSegments: string[],
|
|
42
|
+
c: Compression,
|
|
43
|
+
d: string,
|
|
44
|
+
u: UpdateStrategy,
|
|
45
|
+
i?: number, // time interval in millis
|
|
46
|
+
h?: number, // hash function. 0 for murmur3_32, 1 for murmur3_64
|
|
47
|
+
s?: number, // seed for hash function
|
|
48
|
+
}
|
|
49
|
+
|
|
38
50
|
export interface ISegmentUpdateData {
|
|
39
51
|
type: SEGMENT_UPDATE,
|
|
40
52
|
changeNumber: number,
|
|
@@ -68,6 +80,6 @@ export interface IOccupancyData {
|
|
|
68
80
|
}
|
|
69
81
|
}
|
|
70
82
|
|
|
71
|
-
export type INotificationData = IMySegmentsUpdateData | IMySegmentsUpdateV2Data | ISegmentUpdateData | ISplitUpdateData | ISplitKillData | IControlData | IOccupancyData
|
|
83
|
+
export type INotificationData = IMySegmentsUpdateData | IMySegmentsUpdateV2Data | IMyLargeSegmentsUpdateData | ISegmentUpdateData | ISplitUpdateData | ISplitKillData | IControlData | IOccupancyData
|
|
72
84
|
export type INotificationMessage = { parsedData: INotificationData, channel: string, timestamp: number, data: string }
|
|
73
85
|
export type INotificationError = Event & { parsedData?: any, message?: string }
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { IMySegmentsSyncTask, MySegmentsData } from '../../polling/types';
|
|
2
2
|
import { Backoff } from '../../../utils/Backoff';
|
|
3
3
|
import { IUpdateWorker } from './types';
|
|
4
|
-
import { MY_SEGMENT } from '../../../utils/constants';
|
|
5
4
|
import { ITelemetryTracker } from '../../../trackers/types';
|
|
5
|
+
import { UpdatesFromSSEEnum } from '../../submitters/types';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* MySegmentsUpdateWorker factory
|
|
9
9
|
*/
|
|
10
|
-
export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker): IUpdateWorker {
|
|
10
|
+
export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker, updateType: UpdatesFromSSEEnum): IUpdateWorker {
|
|
11
11
|
|
|
12
12
|
let maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
|
|
13
13
|
let currentChangeNumber = -1;
|
|
14
14
|
let handleNewEvent = false;
|
|
15
15
|
let isHandlingEvent: boolean;
|
|
16
16
|
let _segmentsData: MySegmentsData | undefined; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber
|
|
17
|
+
let _delay: undefined | number;
|
|
18
|
+
let _delayTimeoutID: undefined | number;
|
|
17
19
|
const backoff = new Backoff(__handleMySegmentsUpdateCall);
|
|
18
20
|
|
|
19
21
|
function __handleMySegmentsUpdateCall() {
|
|
@@ -23,10 +25,18 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
23
25
|
const currentMaxChangeNumber = maxChangeNumber;
|
|
24
26
|
|
|
25
27
|
// fetch mySegments revalidating data if cached
|
|
26
|
-
|
|
28
|
+
const syncTask = _delay ?
|
|
29
|
+
new Promise(res => {
|
|
30
|
+
_delayTimeoutID = setTimeout(() => {
|
|
31
|
+
mySegmentsSyncTask.execute(_segmentsData, true).then(res);
|
|
32
|
+
}, _delay);
|
|
33
|
+
}) :
|
|
34
|
+
mySegmentsSyncTask.execute(_segmentsData, true);
|
|
35
|
+
|
|
36
|
+
syncTask.then((result) => {
|
|
27
37
|
if (!isHandlingEvent) return; // halt if `stop` has been called
|
|
28
38
|
if (result !== false) {// Unlike `Splits|SegmentsUpdateWorker`, we cannot use `mySegmentsCache.getChangeNumber` since `/mySegments` endpoint doesn't provide this value.
|
|
29
|
-
if (_segmentsData) telemetryTracker.trackUpdatesFromSSE(
|
|
39
|
+
if (_segmentsData) telemetryTracker.trackUpdatesFromSSE(updateType);
|
|
30
40
|
currentChangeNumber = Math.max(currentChangeNumber, currentMaxChangeNumber); // use `currentMaxChangeNumber`, in case that `maxChangeNumber` was updated during fetch.
|
|
31
41
|
}
|
|
32
42
|
if (handleNewEvent) {
|
|
@@ -47,18 +57,20 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
47
57
|
* @param {number} changeNumber change number of the MY_SEGMENTS_UPDATE notification
|
|
48
58
|
* @param {SegmentsData | undefined} segmentsData might be undefined
|
|
49
59
|
*/
|
|
50
|
-
put(changeNumber: number, segmentsData?: MySegmentsData) {
|
|
60
|
+
put(changeNumber: number, segmentsData?: MySegmentsData, delay?: number) {
|
|
51
61
|
if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber) return;
|
|
52
62
|
|
|
53
63
|
maxChangeNumber = changeNumber;
|
|
54
64
|
handleNewEvent = true;
|
|
55
65
|
_segmentsData = segmentsData;
|
|
66
|
+
_delay = delay;
|
|
56
67
|
|
|
57
68
|
if (backoff.timeoutID || !isHandlingEvent) __handleMySegmentsUpdateCall();
|
|
58
69
|
backoff.reset();
|
|
59
70
|
},
|
|
60
71
|
|
|
61
72
|
stop() {
|
|
73
|
+
clearTimeout(_delayTimeoutID);
|
|
62
74
|
isHandlingEvent = false;
|
|
63
75
|
backoff.reset();
|
|
64
76
|
}
|
|
@@ -30,6 +30,7 @@ export const MY_SEGMENTS_UPDATE_V2 = 'MY_SEGMENTS_UPDATE_V2';
|
|
|
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 MY_LARGE_SEGMENTS_UPDATE = 'MY_LARGE_SEGMENTS_UPDATE';
|
|
33
34
|
|
|
34
35
|
// Control-type push notifications, handled by NotificationKeeper
|
|
35
36
|
export const CONTROL = 'CONTROL';
|
|
@@ -11,17 +11,25 @@ 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 { MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType } from './constants';
|
|
14
|
+
import { MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType, MY_LARGE_SEGMENTS_UPDATE } from './constants';
|
|
15
15
|
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, STREAMING_PARSING_SPLIT_UPDATE } from '../../logger/constants';
|
|
16
|
-
import { KeyList, UpdateStrategy } from './SSEHandler/types';
|
|
16
|
+
import { IMyLargeSegmentsUpdateData, IMySegmentsUpdateV2Data, KeyList, UpdateStrategy } from './SSEHandler/types';
|
|
17
17
|
import { isInBitmap, parseBitmap, parseFFUpdatePayload, parseKeyList } from './parseUtils';
|
|
18
18
|
import { ISet, _Set } from '../../utils/lang/sets';
|
|
19
|
+
import { hash } from '../../utils/murmur3/murmur3';
|
|
19
20
|
import { Hash64, hash64 } from '../../utils/murmur3/murmur3_64';
|
|
20
21
|
import { IAuthTokenPushEnabled } from './AuthClient/types';
|
|
21
|
-
import { TOKEN_REFRESH, AUTH_REJECTION } from '../../utils/constants';
|
|
22
|
+
import { TOKEN_REFRESH, AUTH_REJECTION, MY_LARGE_SEGMENT, MY_SEGMENT } from '../../utils/constants';
|
|
22
23
|
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
23
24
|
import { IUpdateWorker } from './UpdateWorkers/types';
|
|
24
25
|
|
|
26
|
+
export function getDelay(parsedData: Pick<IMyLargeSegmentsUpdateData, 'i' | 'h' | 's'>, matchingKey: string) {
|
|
27
|
+
const interval = parsedData.i || 60000;
|
|
28
|
+
const seed = parsedData.s || 0;
|
|
29
|
+
|
|
30
|
+
return hash(matchingKey, seed) % interval;
|
|
31
|
+
}
|
|
32
|
+
|
|
25
33
|
/**
|
|
26
34
|
* PushManager factory:
|
|
27
35
|
* - for server-side if key is not provided in settings.
|
|
@@ -64,7 +72,7 @@ export function pushManagerFactory(
|
|
|
64
72
|
const userKeyHashes: Record<string, string> = {};
|
|
65
73
|
// [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
|
|
66
74
|
// Hash64 is used to process MY_SEGMENTS_UPDATE_V2 events and dispatch actions to the corresponding MySegmentsUpdateWorker.
|
|
67
|
-
const clients: Record<string, { hash64: Hash64, worker: IUpdateWorker }> = {};
|
|
75
|
+
const clients: Record<string, { hash64: Hash64, worker: IUpdateWorker, workerLarge?: IUpdateWorker }> = {};
|
|
68
76
|
|
|
69
77
|
// [Only for client-side] variable to flag that a new client was added. It is needed to reconnect streaming.
|
|
70
78
|
let connectForNewClient = false;
|
|
@@ -171,7 +179,10 @@ export function pushManagerFactory(
|
|
|
171
179
|
// cancel scheduled fetch retries of Splits, Segments, and MySegments Update Workers
|
|
172
180
|
function stopWorkers() {
|
|
173
181
|
splitsUpdateWorker.stop();
|
|
174
|
-
if (userKey) forOwn(clients, ({ worker }) =>
|
|
182
|
+
if (userKey) forOwn(clients, ({ worker, workerLarge }) => {
|
|
183
|
+
worker.stop();
|
|
184
|
+
workerLarge && workerLarge.stop();
|
|
185
|
+
});
|
|
175
186
|
else segmentsUpdateWorker!.stop();
|
|
176
187
|
}
|
|
177
188
|
|
|
@@ -236,76 +247,98 @@ export function pushManagerFactory(
|
|
|
236
247
|
splitsUpdateWorker.put(parsedData);
|
|
237
248
|
});
|
|
238
249
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
switch (parsedData.u) {
|
|
251
|
-
case UpdateStrategy.BoundedFetchRequest: {
|
|
252
|
-
let bitmap: Uint8Array;
|
|
253
|
-
try {
|
|
254
|
-
bitmap = parseBitmap(parsedData.d, parsedData.c);
|
|
255
|
-
} catch (e) {
|
|
256
|
-
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['BoundedFetchRequest', e]);
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
forOwn(clients, ({ hash64, worker }) => {
|
|
261
|
-
if (isInBitmap(bitmap, hash64.hex)) {
|
|
262
|
-
worker.put(parsedData.changeNumber); // fetch mySegments
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
return;
|
|
250
|
+
function handleMySegmentsUpdate(parsedData: IMySegmentsUpdateV2Data | IMyLargeSegmentsUpdateData) {
|
|
251
|
+
const isLS = parsedData.type === MY_LARGE_SEGMENTS_UPDATE;
|
|
252
|
+
|
|
253
|
+
switch (parsedData.u) {
|
|
254
|
+
case UpdateStrategy.BoundedFetchRequest: {
|
|
255
|
+
let bitmap: Uint8Array;
|
|
256
|
+
try {
|
|
257
|
+
bitmap = parseBitmap(parsedData.d, parsedData.c);
|
|
258
|
+
} catch (e) {
|
|
259
|
+
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['BoundedFetchRequest', e]);
|
|
260
|
+
break;
|
|
266
261
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
} catch (e) {
|
|
274
|
-
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['KeyList', e]);
|
|
275
|
-
break;
|
|
262
|
+
|
|
263
|
+
forOwn(clients, ({ hash64, worker, workerLarge }, matchingKey) => {
|
|
264
|
+
if (isInBitmap(bitmap, hash64.hex)) {
|
|
265
|
+
isLS ?
|
|
266
|
+
workerLarge && workerLarge.put(parsedData.changeNumber, undefined, getDelay(parsedData, matchingKey)) :
|
|
267
|
+
worker.put(parsedData.changeNumber);
|
|
276
268
|
}
|
|
269
|
+
});
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
case UpdateStrategy.KeyList: {
|
|
273
|
+
let keyList: KeyList, added: ISet<string>, removed: ISet<string>;
|
|
274
|
+
try {
|
|
275
|
+
keyList = parseKeyList(parsedData.d, parsedData.c);
|
|
276
|
+
added = new _Set(keyList.a);
|
|
277
|
+
removed = new _Set(keyList.r);
|
|
278
|
+
} catch (e) {
|
|
279
|
+
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['KeyList', e]);
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
277
282
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
283
|
+
forOwn(clients, ({ hash64, worker, workerLarge }) => {
|
|
284
|
+
const add = added.has(hash64.dec) ? true : removed.has(hash64.dec) ? false : undefined;
|
|
285
|
+
if (add !== undefined) {
|
|
286
|
+
isLS ?
|
|
287
|
+
workerLarge && workerLarge.put(parsedData.changeNumber, {
|
|
288
|
+
name: parsedData.largeSegments[0],
|
|
289
|
+
add
|
|
290
|
+
}) :
|
|
281
291
|
worker.put(parsedData.changeNumber, {
|
|
282
292
|
name: parsedData.segmentName,
|
|
283
293
|
add
|
|
284
294
|
});
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
case UpdateStrategy.SegmentRemoval:
|
|
290
|
-
if (!parsedData.segmentName) {
|
|
291
|
-
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['SegmentRemoval', 'No segment name was provided']);
|
|
292
|
-
break;
|
|
293
295
|
}
|
|
296
|
+
});
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
case UpdateStrategy.SegmentRemoval:
|
|
300
|
+
if ((isLS && parsedData.largeSegments.length === 0) || (!isLS && !parsedData.segmentName)) {
|
|
301
|
+
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE_V2, ['SegmentRemoval', 'No segment name was provided']);
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
294
304
|
|
|
295
|
-
|
|
305
|
+
forOwn(clients, ({ worker, workerLarge }) => {
|
|
306
|
+
isLS ?
|
|
307
|
+
workerLarge && parsedData.largeSegments.forEach(largeSegment => {
|
|
308
|
+
workerLarge.put(parsedData.changeNumber, {
|
|
309
|
+
name: largeSegment,
|
|
310
|
+
add: false
|
|
311
|
+
});
|
|
312
|
+
}) :
|
|
296
313
|
worker.put(parsedData.changeNumber, {
|
|
297
314
|
name: parsedData.segmentName,
|
|
298
315
|
add: false
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
303
320
|
|
|
304
|
-
|
|
305
|
-
|
|
321
|
+
// `UpdateStrategy.UnboundedFetchRequest` and fallbacks of other cases
|
|
322
|
+
forOwn(clients, ({ worker, workerLarge }, matchingKey) => {
|
|
323
|
+
isLS ?
|
|
324
|
+
workerLarge && workerLarge.put(parsedData.changeNumber, undefined, getDelay(parsedData, matchingKey)) :
|
|
306
325
|
worker.put(parsedData.changeNumber);
|
|
307
|
-
});
|
|
308
326
|
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (userKey) {
|
|
330
|
+
pushEmitter.on(MY_SEGMENTS_UPDATE, function handleMySegmentsUpdate(parsedData, channel) {
|
|
331
|
+
const userKeyHash = channel.split('_')[2];
|
|
332
|
+
const userKey = userKeyHashes[userKeyHash];
|
|
333
|
+
if (userKey && clients[userKey]) { // check existence since it can be undefined if client has been destroyed
|
|
334
|
+
clients[userKey].worker.put(
|
|
335
|
+
parsedData.changeNumber,
|
|
336
|
+
parsedData.includesPayload ? parsedData.segmentList ? parsedData.segmentList : [] : undefined);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
pushEmitter.on(MY_SEGMENTS_UPDATE_V2, handleMySegmentsUpdate);
|
|
341
|
+
pushEmitter.on(MY_LARGE_SEGMENTS_UPDATE, handleMySegmentsUpdate);
|
|
309
342
|
} else {
|
|
310
343
|
pushEmitter.on(SEGMENT_UPDATE, segmentsUpdateWorker!.put);
|
|
311
344
|
}
|
|
@@ -328,7 +361,7 @@ export function pushManagerFactory(
|
|
|
328
361
|
if (disabled || disconnected === false) return;
|
|
329
362
|
disconnected = false;
|
|
330
363
|
|
|
331
|
-
if (userKey) this.add(userKey, pollingManager.segmentsSyncTask
|
|
364
|
+
if (userKey) this.add(userKey, pollingManager.segmentsSyncTask, pollingManager.largeSegmentsSyncTask!); // client-side
|
|
332
365
|
else setTimeout(connectPush); // server-side runs in next cycle as in client-side, for consistency with client-side
|
|
333
366
|
},
|
|
334
367
|
|
|
@@ -338,12 +371,16 @@ export function pushManagerFactory(
|
|
|
338
371
|
},
|
|
339
372
|
|
|
340
373
|
// [Only for client-side]
|
|
341
|
-
add(userKey: string, mySegmentsSyncTask: IMySegmentsSyncTask) {
|
|
374
|
+
add(userKey: string, mySegmentsSyncTask: IMySegmentsSyncTask, myLargeSegmentsSyncTask?: IMySegmentsSyncTask) {
|
|
342
375
|
const hash = hashUserKey(userKey);
|
|
343
376
|
|
|
344
377
|
if (!userKeyHashes[hash]) {
|
|
345
378
|
userKeyHashes[hash] = userKey;
|
|
346
|
-
clients[userKey] = {
|
|
379
|
+
clients[userKey] = {
|
|
380
|
+
hash64: hash64(userKey),
|
|
381
|
+
worker: MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker, MY_SEGMENT),
|
|
382
|
+
workerLarge: myLargeSegmentsSyncTask ? MySegmentsUpdateWorker(myLargeSegmentsSyncTask, telemetryTracker, MY_LARGE_SEGMENT) : undefined
|
|
383
|
+
};
|
|
347
384
|
connectForNewClient = true; // we must reconnect on start, to listen the channel for the new user key
|
|
348
385
|
|
|
349
386
|
// Reconnects in case of a new client.
|