@splitsoftware/splitio-commons 1.3.1-rc.1 → 1.3.2-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/cjs/consent/sdkUserConsent.js +1 -1
- package/cjs/listeners/browser.js +5 -4
- package/cjs/logger/constants.js +2 -1
- package/cjs/logger/messages/error.js +2 -1
- package/cjs/logger/messages/info.js +3 -3
- package/cjs/logger/messages/warn.js +2 -2
- package/cjs/sdkClient/client.js +17 -3
- package/cjs/sdkClient/sdkClient.js +4 -1
- package/cjs/sdkFactory/index.js +16 -19
- package/cjs/services/splitApi.js +15 -14
- package/cjs/services/splitHttpClient.js +4 -1
- package/cjs/storages/AbstractSegmentsCacheSync.js +0 -5
- package/cjs/storages/KeyBuilderSS.js +12 -19
- package/cjs/storages/findLatencyIndex.js +11 -6
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +13 -1
- package/cjs/storages/inLocalStorage/index.js +4 -1
- package/cjs/storages/inMemory/InMemoryStorage.js +2 -0
- package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -0
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +6 -0
- package/cjs/storages/inMemory/SegmentsCacheInMemory.js +6 -0
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +165 -0
- package/cjs/storages/inRedis/TelemetryCacheInRedis.js +29 -0
- package/cjs/storages/inRedis/index.js +2 -4
- package/cjs/storages/pluggable/TelemetryCachePluggable.js +27 -0
- package/cjs/storages/pluggable/index.js +2 -1
- package/cjs/sync/polling/pollingManagerCS.js +1 -1
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +2 -2
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +0 -3
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -8
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +3 -6
- package/cjs/sync/streaming/SSEHandler/NotificationKeeper.js +20 -13
- package/cjs/sync/streaming/SSEHandler/index.js +21 -15
- package/cjs/sync/streaming/pushManager.js +7 -4
- package/cjs/sync/submitters/eventsSubmitter.js +28 -0
- package/cjs/sync/submitters/{impressionCountsSyncTask.js → impressionCountsSubmitter.js} +10 -7
- package/cjs/sync/submitters/{impressionsSyncTask.js → impressionsSubmitter.js} +8 -8
- package/cjs/sync/submitters/{submitterSyncTask.js → submitter.js} +34 -13
- package/cjs/sync/submitters/submitterManager.js +12 -10
- package/cjs/sync/submitters/telemetrySubmitter.js +128 -0
- package/cjs/sync/syncManagerOnline.js +6 -2
- package/cjs/trackers/eventTracker.js +5 -1
- package/cjs/trackers/impressionsTracker.js +9 -1
- package/cjs/trackers/telemetryTracker.js +65 -0
- package/cjs/utils/constants/index.js +40 -1
- package/cjs/utils/inputValidation/apiKey.js +12 -11
- package/cjs/utils/settingsValidation/index.js +20 -6
- package/cjs/utils/settingsValidation/url.js +4 -0
- package/cjs/utils/timeTracker/index.js +1 -0
- package/cjs/utils/timeTracker/timer.js +2 -2
- package/esm/consent/sdkUserConsent.js +1 -1
- package/esm/listeners/browser.js +3 -2
- package/esm/logger/constants.js +1 -0
- package/esm/logger/messages/error.js +2 -1
- package/esm/logger/messages/info.js +3 -3
- package/esm/logger/messages/warn.js +2 -2
- package/esm/sdkClient/client.js +18 -4
- package/esm/sdkClient/sdkClient.js +4 -1
- package/esm/sdkFactory/index.js +16 -19
- package/esm/services/splitApi.js +15 -14
- package/esm/services/splitHttpClient.js +4 -1
- package/esm/storages/AbstractSegmentsCacheSync.js +0 -5
- package/esm/storages/KeyBuilderSS.js +12 -19
- package/esm/storages/findLatencyIndex.js +11 -6
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +13 -1
- package/esm/storages/inLocalStorage/index.js +5 -2
- package/esm/storages/inMemory/InMemoryStorage.js +3 -1
- package/esm/storages/inMemory/InMemoryStorageCS.js +4 -1
- package/esm/storages/inMemory/MySegmentsCacheInMemory.js +6 -0
- package/esm/storages/inMemory/SegmentsCacheInMemory.js +6 -0
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +161 -0
- package/esm/storages/inRedis/TelemetryCacheInRedis.js +26 -0
- package/esm/storages/inRedis/index.js +2 -4
- package/esm/storages/pluggable/TelemetryCachePluggable.js +24 -0
- package/esm/storages/pluggable/index.js +2 -1
- package/esm/sync/polling/pollingManagerCS.js +1 -1
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +2 -2
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +0 -3
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -8
- package/esm/sync/polling/updaters/splitChangesUpdater.js +3 -6
- package/esm/sync/streaming/SSEHandler/NotificationKeeper.js +8 -1
- package/esm/sync/streaming/SSEHandler/index.js +21 -15
- package/esm/sync/streaming/pushManager.js +7 -4
- package/esm/sync/submitters/eventsSubmitter.js +24 -0
- package/esm/sync/submitters/{impressionCountsSyncTask.js → impressionCountsSubmitter.js} +8 -5
- package/esm/sync/submitters/{impressionsSyncTask.js → impressionsSubmitter.js} +6 -6
- package/esm/sync/submitters/submitter.js +60 -0
- package/esm/sync/submitters/submitterManager.js +12 -10
- package/esm/sync/submitters/telemetrySubmitter.js +122 -0
- package/esm/sync/syncManagerOnline.js +6 -2
- package/esm/trackers/eventTracker.js +6 -2
- package/esm/trackers/impressionsTracker.js +10 -2
- package/esm/trackers/telemetryTracker.js +61 -0
- package/esm/utils/constants/index.js +38 -0
- package/esm/utils/inputValidation/apiKey.js +2 -1
- package/esm/utils/settingsValidation/index.js +18 -4
- package/esm/utils/settingsValidation/url.js +4 -0
- package/esm/utils/timeTracker/index.js +1 -0
- package/esm/utils/timeTracker/timer.js +2 -2
- package/package.json +1 -1
- package/src/consent/sdkUserConsent.ts +1 -1
- package/src/listeners/browser.ts +3 -2
- package/src/logger/constants.ts +1 -0
- package/src/logger/messages/error.ts +2 -1
- package/src/logger/messages/info.ts +3 -3
- package/src/logger/messages/warn.ts +2 -2
- package/src/sdkClient/client.ts +23 -4
- package/src/sdkClient/sdkClient.ts +4 -1
- package/src/sdkFactory/index.ts +22 -24
- package/src/sdkFactory/types.ts +32 -15
- package/src/services/splitApi.ts +17 -14
- package/src/services/splitHttpClient.ts +6 -3
- package/src/services/types.ts +7 -5
- package/src/storages/AbstractSegmentsCacheSync.ts +8 -3
- package/src/storages/KeyBuilderSS.ts +13 -50
- package/src/storages/findLatencyIndex.ts +12 -3
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +13 -1
- package/src/storages/inLocalStorage/index.ts +5 -2
- package/src/storages/inMemory/InMemoryStorage.ts +3 -1
- package/src/storages/inMemory/InMemoryStorageCS.ts +4 -1
- package/src/storages/inMemory/MySegmentsCacheInMemory.ts +8 -0
- package/src/storages/inMemory/SegmentsCacheInMemory.ts +6 -0
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +210 -0
- package/src/storages/inRedis/TelemetryCacheInRedis.ts +29 -0
- package/src/storages/inRedis/index.ts +2 -4
- package/src/storages/pluggable/TelemetryCachePluggable.ts +26 -0
- package/src/storages/pluggable/index.ts +2 -1
- package/src/storages/types.ts +84 -32
- package/src/sync/offline/syncManagerOffline.ts +4 -3
- package/src/sync/polling/pollingManagerCS.ts +3 -3
- package/src/sync/polling/pollingManagerSS.ts +2 -2
- package/src/sync/polling/syncTasks/splitsSyncTask.ts +2 -0
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +0 -4
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +2 -10
- package/src/sync/polling/updaters/splitChangesUpdater.ts +3 -6
- package/src/sync/streaming/SSEHandler/NotificationKeeper.ts +11 -1
- package/src/sync/streaming/SSEHandler/index.ts +21 -14
- package/src/sync/streaming/pushManager.ts +11 -7
- package/src/sync/submitters/eventsSubmitter.ts +35 -0
- package/src/sync/submitters/{impressionCountsSyncTask.ts → impressionCountsSubmitter.ts} +15 -15
- package/src/sync/submitters/{impressionsSyncTask.ts → impressionsSubmitter.ts} +12 -16
- package/src/sync/submitters/{submitterSyncTask.ts → submitter.ts} +33 -15
- package/src/sync/submitters/submitterManager.ts +14 -11
- package/src/sync/submitters/telemetrySubmitter.ts +143 -0
- package/src/sync/submitters/types.ts +123 -0
- package/src/sync/syncManagerOnline.ts +13 -7
- package/src/sync/types.ts +0 -15
- package/src/trackers/eventTracker.ts +7 -3
- package/src/trackers/impressionsTracker.ts +11 -3
- package/src/trackers/telemetryTracker.ts +63 -0
- package/src/trackers/types.ts +24 -0
- package/src/types.ts +35 -6
- package/src/utils/constants/index.ts +45 -0
- package/src/utils/inputValidation/apiKey.ts +2 -1
- package/src/utils/settingsValidation/index.ts +18 -4
- package/src/utils/settingsValidation/url.ts +4 -0
- package/src/utils/timeTracker/index.ts +1 -1
- package/src/utils/timeTracker/timer.ts +3 -3
- package/types/logger/constants.d.ts +1 -0
- package/types/sdkFactory/types.d.ts +29 -14
- package/types/services/splitApi.d.ts +2 -1
- package/types/services/types.d.ts +8 -5
- package/types/storages/AbstractSegmentsCacheSync.d.ts +7 -3
- package/types/storages/KeyBuilderSS.d.ts +3 -3
- package/types/storages/findLatencyIndex.d.ts +7 -1
- package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +2 -0
- package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +2 -0
- package/types/storages/inMemory/SegmentsCacheInMemory.d.ts +1 -0
- package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -2
- package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +3 -3
- package/types/storages/pluggable/TelemetryCachePluggable.d.ts +2 -2
- package/types/storages/types.d.ts +71 -22
- package/types/sync/offline/syncManagerOffline.d.ts +3 -2
- package/types/sync/polling/pollingManagerCS.d.ts +2 -2
- package/types/sync/polling/pollingManagerSS.d.ts +2 -2
- package/types/sync/polling/syncTasks/splitsSyncTask.d.ts +1 -1
- package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -1
- package/types/sync/streaming/SSEHandler/NotificationKeeper.d.ts +2 -1
- package/types/sync/streaming/SSEHandler/index.d.ts +2 -1
- package/types/sync/streaming/pushManager.d.ts +2 -2
- package/types/sync/submitters/eventsSubmitter.d.ts +5 -0
- package/types/sync/submitters/impressionCountsSubmitter.d.ts +10 -0
- package/types/sync/submitters/impressionsSubmitter.d.ts +11 -0
- package/types/sync/submitters/submitter.d.ts +12 -0
- package/types/sync/submitters/submitterManager.d.ts +2 -2
- package/types/sync/submitters/telemetrySubmitter.d.ts +24 -0
- package/types/sync/submitters/telemetrySyncTask.d.ts +0 -27
- package/types/sync/submitters/types.d.ts +107 -0
- package/types/sync/syncManagerOnline.d.ts +3 -2
- package/types/sync/types.d.ts +0 -13
- package/types/trackers/eventTracker.d.ts +2 -2
- package/types/trackers/impressionsTracker.d.ts +2 -2
- package/types/trackers/telemetryTracker.d.ts +2 -3
- package/types/trackers/types.d.ts +22 -0
- package/types/types.d.ts +33 -4
- package/types/utils/constants/index.d.ts +37 -0
- package/types/utils/inputValidation/apiKey.d.ts +1 -0
- package/types/utils/settingsValidation/index.d.ts +40 -0
- package/types/utils/timeTracker/index.d.ts +1 -1
- package/types/utils/timeTracker/timer.d.ts +1 -1
- package/cjs/storages/inMemory/CountsCacheInMemory.js +0 -38
- package/cjs/storages/inMemory/LatenciesCacheInMemory.js +0 -43
- package/cjs/storages/inRedis/CountsCacheInRedis.js +0 -16
- package/cjs/storages/inRedis/LatenciesCacheInRedis.js +0 -18
- package/cjs/sync/submitters/eventsSyncTask.js +0 -44
- package/cjs/sync/submitters/metricsSyncTask.js +0 -31
- package/esm/storages/inMemory/CountsCacheInMemory.js +0 -35
- package/esm/storages/inMemory/LatenciesCacheInMemory.js +0 -40
- package/esm/storages/inRedis/CountsCacheInRedis.js +0 -13
- package/esm/storages/inRedis/LatenciesCacheInRedis.js +0 -15
- package/esm/sync/submitters/eventsSyncTask.js +0 -40
- package/esm/sync/submitters/metricsSyncTask.js +0 -26
- package/esm/sync/submitters/submitterSyncTask.js +0 -40
- package/src/storages/inMemory/CountsCacheInMemory.ts +0 -37
- package/src/storages/inMemory/LatenciesCacheInMemory.ts +0 -45
- package/src/storages/inRedis/CountsCacheInRedis.ts +0 -20
- package/src/storages/inRedis/LatenciesCacheInRedis.ts +0 -23
- package/src/sync/submitters/eventsSyncTask.ts +0 -57
- package/src/sync/submitters/metricsSyncTask.ts +0 -49
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies } from '../../sync/submitters/types';
|
|
2
|
+
import { findLatencyIndex } from '../findLatencyIndex';
|
|
3
|
+
import { ITelemetryCacheSync } from '../types';
|
|
4
|
+
|
|
5
|
+
const MAX_STREAMING_EVENTS = 20;
|
|
6
|
+
const MAX_TAGS = 10;
|
|
7
|
+
|
|
8
|
+
function newBuckets() {
|
|
9
|
+
// MAX_LATENCY_BUCKET_COUNT (length) is 23;
|
|
10
|
+
return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const ACCEPTANCE_RANGE = 0.001;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Used on client-side. 0.1% of instances will track telemetry
|
|
17
|
+
*/
|
|
18
|
+
export function shouldRecordTelemetry() {
|
|
19
|
+
return Math.random() <= ACCEPTANCE_RANGE;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class TelemetryCacheInMemory implements ITelemetryCacheSync {
|
|
23
|
+
|
|
24
|
+
private timeUntilReady?: number;
|
|
25
|
+
|
|
26
|
+
getTimeUntilReady() {
|
|
27
|
+
return this.timeUntilReady;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
recordTimeUntilReady(ms: number) {
|
|
31
|
+
this.timeUntilReady = ms;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private timeUntilReadyFromCache?: number;
|
|
35
|
+
|
|
36
|
+
getTimeUntilReadyFromCache() {
|
|
37
|
+
return this.timeUntilReadyFromCache;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
recordTimeUntilReadyFromCache(ms: number) {
|
|
41
|
+
this.timeUntilReadyFromCache = ms;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private notReadyUsage = 0;
|
|
45
|
+
|
|
46
|
+
getNonReadyUsage() {
|
|
47
|
+
return this.notReadyUsage;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
recordNonReadyUsage() {
|
|
51
|
+
this.notReadyUsage++;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private impressionStats = [0, 0, 0];
|
|
55
|
+
|
|
56
|
+
getImpressionStats(type: ImpressionDataType) {
|
|
57
|
+
return this.impressionStats[type];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
recordImpressionStats(type: ImpressionDataType, count: number) {
|
|
61
|
+
this.impressionStats[type] += count;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private eventStats = [0, 0];
|
|
65
|
+
|
|
66
|
+
getEventStats(type: EventDataType) {
|
|
67
|
+
return this.eventStats[type];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
recordEventStats(type: EventDataType, count: number) {
|
|
71
|
+
this.eventStats[type] += count;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// @ts-expect-error
|
|
75
|
+
private lastSync: LastSync = {};
|
|
76
|
+
|
|
77
|
+
getLastSynchronization() {
|
|
78
|
+
return this.lastSync;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
recordSuccessfulSync(resource: OperationType, timeMs: number) {
|
|
82
|
+
this.lastSync[resource] = timeMs;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// @ts-expect-error
|
|
86
|
+
private httpErrors: HttpErrors = {};
|
|
87
|
+
|
|
88
|
+
popHttpErrors() {
|
|
89
|
+
const result = this.httpErrors; // @ts-expect-error
|
|
90
|
+
this.httpErrors = {};
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
recordHttpError(resource: OperationType, status: number) {
|
|
95
|
+
if (!this.httpErrors[resource]) this.httpErrors[resource] = {};
|
|
96
|
+
if (!this.httpErrors[resource][status]) {
|
|
97
|
+
this.httpErrors[resource][status] = 1;
|
|
98
|
+
} else {
|
|
99
|
+
this.httpErrors[resource][status]++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// @ts-expect-error
|
|
104
|
+
private httpLatencies: HttpLatencies = {};
|
|
105
|
+
|
|
106
|
+
popHttpLatencies() {
|
|
107
|
+
const result = this.httpLatencies; // @ts-expect-error
|
|
108
|
+
this.httpLatencies = {};
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
recordHttpLatency(resource: OperationType, latencyMs: number) {
|
|
113
|
+
if (!this.httpLatencies[resource]) {
|
|
114
|
+
this.httpLatencies[resource] = newBuckets();
|
|
115
|
+
}
|
|
116
|
+
this.httpLatencies[resource][findLatencyIndex(latencyMs)]++;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private authRejections = 0;
|
|
120
|
+
|
|
121
|
+
popAuthRejections() {
|
|
122
|
+
const result = this.authRejections;
|
|
123
|
+
this.authRejections = 0;
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
recordAuthRejections() {
|
|
128
|
+
this.authRejections++;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private tokenRefreshes = 0;
|
|
132
|
+
|
|
133
|
+
popTokenRefreshes() {
|
|
134
|
+
const result = this.tokenRefreshes;
|
|
135
|
+
this.tokenRefreshes = 0;
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
recordTokenRefreshes() {
|
|
140
|
+
this.tokenRefreshes++;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private streamingEvents: StreamingEvent[] = []
|
|
144
|
+
|
|
145
|
+
popStreamingEvents() {
|
|
146
|
+
return this.streamingEvents.splice(0);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
recordStreamingEvents(streamingEvent: StreamingEvent) {
|
|
150
|
+
if (this.streamingEvents.length < MAX_STREAMING_EVENTS) {
|
|
151
|
+
this.streamingEvents.push(streamingEvent);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private tags: string[] = [];
|
|
156
|
+
|
|
157
|
+
popTags() {
|
|
158
|
+
return this.tags.splice(0);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
addTag(tag: string) {
|
|
162
|
+
if (this.tags.length < MAX_TAGS) {
|
|
163
|
+
this.tags.push(tag);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private sessionLength?: number;
|
|
168
|
+
|
|
169
|
+
getSessionLength() {
|
|
170
|
+
return this.sessionLength;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
recordSessionLength(ms: number) {
|
|
174
|
+
this.sessionLength = ms;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// @ts-expect-error
|
|
178
|
+
private exceptions: MethodExceptions = {};
|
|
179
|
+
|
|
180
|
+
popExceptions() {
|
|
181
|
+
const result = this.exceptions; // @ts-expect-error
|
|
182
|
+
this.exceptions = {};
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
recordException(method: Method) {
|
|
187
|
+
if (!this.exceptions[method]) {
|
|
188
|
+
this.exceptions[method] = 1;
|
|
189
|
+
} else {
|
|
190
|
+
this.exceptions[method]++;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// @ts-expect-error
|
|
195
|
+
private latencies: MethodLatencies = {};
|
|
196
|
+
|
|
197
|
+
popLatencies() {
|
|
198
|
+
const result = this.latencies; // @ts-expect-error
|
|
199
|
+
this.latencies = {};
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
recordLatency(method: Method, latencyMs: number) {
|
|
204
|
+
if (!this.latencies[method]) {
|
|
205
|
+
this.latencies[method] = newBuckets();
|
|
206
|
+
}
|
|
207
|
+
this.latencies[method][findLatencyIndex(latencyMs)]++;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ILogger } from '../../logger/types';
|
|
2
|
+
import { Method } from '../../sync/submitters/types';
|
|
3
|
+
import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
4
|
+
import { ITelemetryCacheAsync } from '../types';
|
|
5
|
+
import { findLatencyIndex } from '../findLatencyIndex';
|
|
6
|
+
import { Redis } from 'ioredis';
|
|
7
|
+
|
|
8
|
+
export class TelemetryCacheInRedis implements ITelemetryCacheAsync {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Create a Telemetry cache that uses Redis as storage.
|
|
12
|
+
* @param log Logger instance.
|
|
13
|
+
* @param keys Key builder.
|
|
14
|
+
* @param redis Redis client.
|
|
15
|
+
*/
|
|
16
|
+
constructor(private readonly log: ILogger, private readonly keys: KeyBuilderSS, private readonly redis: Redis) { }
|
|
17
|
+
|
|
18
|
+
recordLatency(method: Method, latencyMs: number) {
|
|
19
|
+
const [key, field] = this.keys.buildLatencyKey(method, findLatencyIndex(latencyMs)).split('::');
|
|
20
|
+
return this.redis.hincrby(key, field, 1)
|
|
21
|
+
.catch(() => { /* Handle rejections for telemetry */ });
|
|
22
|
+
}
|
|
23
|
+
recordException(method: Method) {
|
|
24
|
+
const [key, field] = this.keys.buildExceptionKey(method).split('::');
|
|
25
|
+
return this.redis.hincrby(key, field, 1)
|
|
26
|
+
.catch(() => { /* Handle rejections for telemetry */ });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
@@ -6,9 +6,8 @@ import { SplitsCacheInRedis } from './SplitsCacheInRedis';
|
|
|
6
6
|
import { SegmentsCacheInRedis } from './SegmentsCacheInRedis';
|
|
7
7
|
import { ImpressionsCacheInRedis } from './ImpressionsCacheInRedis';
|
|
8
8
|
import { EventsCacheInRedis } from './EventsCacheInRedis';
|
|
9
|
-
import { LatenciesCacheInRedis } from './LatenciesCacheInRedis';
|
|
10
|
-
import { CountsCacheInRedis } from './CountsCacheInRedis';
|
|
11
9
|
import { STORAGE_REDIS } from '../../utils/constants';
|
|
10
|
+
import { TelemetryCacheInRedis } from './TelemetryCacheInRedis';
|
|
12
11
|
|
|
13
12
|
export interface InRedisStorageOptions {
|
|
14
13
|
prefix?: string
|
|
@@ -38,8 +37,7 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
|
|
|
38
37
|
segments: new SegmentsCacheInRedis(log, keys, redisClient),
|
|
39
38
|
impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
|
|
40
39
|
events: new EventsCacheInRedis(log, keys.buildEventsKey(), redisClient, metadata),
|
|
41
|
-
|
|
42
|
-
counts: new CountsCacheInRedis(keys, redisClient),
|
|
40
|
+
telemetry: new TelemetryCacheInRedis(log, keys, redisClient),
|
|
43
41
|
|
|
44
42
|
// When using REDIS we should:
|
|
45
43
|
// 1- Disconnect from the storage
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ILogger } from '../../logger/types';
|
|
2
|
+
import { Method } from '../../sync/submitters/types';
|
|
3
|
+
import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
4
|
+
import { IPluggableStorageWrapper, ITelemetryCacheAsync } from '../types';
|
|
5
|
+
import { findLatencyIndex } from '../findLatencyIndex';
|
|
6
|
+
|
|
7
|
+
export class TelemetryCachePluggable implements ITelemetryCacheAsync {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create a Telemetry cache that uses a storage wrapper.
|
|
11
|
+
* @param log Logger instance.
|
|
12
|
+
* @param keys Key builder.
|
|
13
|
+
* @param wrapper Adapted wrapper storage.
|
|
14
|
+
*/
|
|
15
|
+
constructor(private readonly log: ILogger, private readonly keys: KeyBuilderSS, private readonly wrapper: IPluggableStorageWrapper) { }
|
|
16
|
+
|
|
17
|
+
recordLatency(method: Method, latencyMs: number) {
|
|
18
|
+
return this.wrapper.incr(this.keys.buildLatencyKey(method, findLatencyIndex(latencyMs)))
|
|
19
|
+
.catch(() => { /* Handle rejections for telemetry */ });
|
|
20
|
+
}
|
|
21
|
+
recordException(method: Method) {
|
|
22
|
+
return this.wrapper.incr(this.keys.buildExceptionKey(method))
|
|
23
|
+
.catch(() => { /* Handle rejections for telemetry */ });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
|
@@ -77,7 +77,8 @@ export function PluggableStorage(options: PluggableStorageOptions): IStorageAsyn
|
|
|
77
77
|
impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
|
|
78
78
|
impressionCounts: optimize ? new ImpressionCountsCacheInMemory() : undefined,
|
|
79
79
|
events: isPartialConsumer ? promisifyEventsTrack(new EventsCacheInMemory(eventsQueueSize)) : new EventsCachePluggable(log, keys.buildEventsKey(), wrapper, metadata),
|
|
80
|
-
// @TODO
|
|
80
|
+
// @TODO Not using TelemetryCachePluggable yet, because it is not supported by the Split Synchronizer
|
|
81
|
+
// telemetry: isPartialConsumer ? new TelemetryCacheInMemory() : new TelemetryCachePluggable(log, keys, wrapper),
|
|
81
82
|
|
|
82
83
|
// Disconnect the underlying storage
|
|
83
84
|
destroy() {
|
package/src/storages/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MaybeThenable, IMetadata, ISplitFiltersValidation } from '../dtos/types';
|
|
2
2
|
import { ILogger } from '../logger/types';
|
|
3
|
-
import { StoredEventWithMetadata, StoredImpressionWithMetadata } from '../sync/submitters/types';
|
|
3
|
+
import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent } from '../sync/submitters/types';
|
|
4
4
|
import { SplitIO, ImpressionDTO, SDKMode } from '../types';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -262,6 +262,7 @@ export interface ISegmentsCacheSync extends ISegmentsCacheBase {
|
|
|
262
262
|
isInSegment(name: string, key?: string): boolean
|
|
263
263
|
registerSegments(names: string[]): boolean
|
|
264
264
|
getRegisteredSegments(): string[]
|
|
265
|
+
getKeysCount(): number // only used for telemetry
|
|
265
266
|
setChangeNumber(name: string, changeNumber: number): boolean
|
|
266
267
|
getChangeNumber(name: string): number
|
|
267
268
|
resetSegments(names: string[]): boolean // only for Sync Client-Side
|
|
@@ -331,11 +332,13 @@ export interface IRecorderCacheProducerAsync<T> {
|
|
|
331
332
|
|
|
332
333
|
export interface IImpressionsCacheAsync extends IImpressionsCacheBase, IRecorderCacheProducerAsync<StoredImpressionWithMetadata[]> {
|
|
333
334
|
// Consumer API method, used by impressions tracker (in standalone and consumer modes) to push data into.
|
|
335
|
+
// The result promise can reject.
|
|
334
336
|
track(data: ImpressionDTO[]): Promise<void>
|
|
335
337
|
}
|
|
336
338
|
|
|
337
339
|
export interface IEventsCacheAsync extends IEventsCacheBase, IRecorderCacheProducerAsync<StoredEventWithMetadata[]> {
|
|
338
340
|
// Consumer API method, used by events tracker (in standalone and consumer modes) to push data into.
|
|
341
|
+
// The result promise cannot reject.
|
|
339
342
|
track(data: SplitIO.EventData, size?: number): Promise<boolean>
|
|
340
343
|
}
|
|
341
344
|
|
|
@@ -354,31 +357,86 @@ export interface IImpressionCountsCacheSync extends IRecorderCacheProducerSync<R
|
|
|
354
357
|
}
|
|
355
358
|
|
|
356
359
|
|
|
357
|
-
/**
|
|
358
|
-
|
|
360
|
+
/**
|
|
361
|
+
* Telemetry storage interface for standalone and partial consumer modes.
|
|
362
|
+
* Methods are sync because data is stored in memory.
|
|
363
|
+
*/
|
|
359
364
|
|
|
360
|
-
export interface
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
+
export interface ITelemetryInitConsumerSync {
|
|
366
|
+
getTimeUntilReady(): number | undefined;
|
|
367
|
+
getTimeUntilReadyFromCache(): number | undefined;
|
|
368
|
+
getNonReadyUsage(): number;
|
|
369
|
+
// 'active factories' and 'redundant factories' are not tracked in the storage. They are derived from `usedKeysMap`
|
|
365
370
|
}
|
|
366
371
|
|
|
367
|
-
export interface
|
|
368
|
-
|
|
372
|
+
export interface ITelemetryRuntimeConsumerSync {
|
|
373
|
+
getImpressionStats(type: ImpressionDataType): number;
|
|
374
|
+
getEventStats(type: EventDataType): number;
|
|
375
|
+
getLastSynchronization(): LastSync;
|
|
376
|
+
popHttpErrors(): HttpErrors;
|
|
377
|
+
popHttpLatencies(): HttpLatencies;
|
|
378
|
+
popAuthRejections(): number;
|
|
379
|
+
popTokenRefreshes(): number;
|
|
380
|
+
popStreamingEvents(): Array<StreamingEvent>;
|
|
381
|
+
popTags(): Array<string> | undefined;
|
|
382
|
+
getSessionLength(): number | undefined;
|
|
369
383
|
}
|
|
370
384
|
|
|
371
|
-
export interface
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
385
|
+
export interface ITelemetryEvaluationConsumerSync {
|
|
386
|
+
popExceptions(): MethodExceptions;
|
|
387
|
+
popLatencies(): MethodLatencies;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export interface ITelemetryStorageConsumerSync extends ITelemetryInitConsumerSync, ITelemetryRuntimeConsumerSync, ITelemetryEvaluationConsumerSync { }
|
|
391
|
+
|
|
392
|
+
export interface ITelemetryInitProducerSync {
|
|
393
|
+
recordTimeUntilReady(ms: number): void;
|
|
394
|
+
recordTimeUntilReadyFromCache(ms: number): void;
|
|
395
|
+
recordNonReadyUsage(): void;
|
|
396
|
+
// 'active factories' and 'redundant factories' are not tracked in the storage. They are derived from `usedKeysMap`
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export interface ITelemetryRuntimeProducerSync {
|
|
400
|
+
addTag(tag: string): void;
|
|
401
|
+
recordImpressionStats(type: ImpressionDataType, count: number): void;
|
|
402
|
+
recordEventStats(type: EventDataType, count: number): void;
|
|
403
|
+
recordSuccessfulSync(resource: OperationType, timeMs: number): void;
|
|
404
|
+
recordHttpError(resource: OperationType, status: number): void;
|
|
405
|
+
recordHttpLatency(resource: OperationType, latencyMs: number): void;
|
|
406
|
+
recordAuthRejections(): void;
|
|
407
|
+
recordTokenRefreshes(): void;
|
|
408
|
+
recordStreamingEvents(streamingEvent: StreamingEvent): void;
|
|
409
|
+
recordSessionLength(ms: number): void;
|
|
376
410
|
}
|
|
377
411
|
|
|
378
|
-
export interface
|
|
379
|
-
|
|
412
|
+
export interface ITelemetryEvaluationProducerSync {
|
|
413
|
+
recordLatency(method: Method, latencyMs: number): void;
|
|
414
|
+
recordException(method: Method): void;
|
|
380
415
|
}
|
|
381
416
|
|
|
417
|
+
export interface ITelemetryStorageProducerSync extends ITelemetryInitProducerSync, ITelemetryRuntimeProducerSync, ITelemetryEvaluationProducerSync { }
|
|
418
|
+
|
|
419
|
+
export interface ITelemetryCacheSync extends ITelemetryStorageConsumerSync, ITelemetryStorageProducerSync { }
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Telemetry storage interface for consumer mode.
|
|
423
|
+
* Methods are async because data is stored in Redis or a pluggable storage.
|
|
424
|
+
*/
|
|
425
|
+
|
|
426
|
+
export interface ITelemetryEvaluationConsumerAsync {
|
|
427
|
+
popExceptions(): Promise<MethodExceptions>;
|
|
428
|
+
popLatencies(): Promise<MethodLatencies>;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export interface ITelemetryEvaluationProducerAsync {
|
|
432
|
+
recordLatency(method: Method, latencyMs: number): Promise<any>;
|
|
433
|
+
recordException(method: Method): Promise<any>;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// ATM it only implements the producer API, used by the SDK in consumer mode.
|
|
437
|
+
// @TODO implement consumer API for JS Synchronizer.
|
|
438
|
+
export interface ITelemetryCacheAsync extends ITelemetryEvaluationProducerAsync { }
|
|
439
|
+
|
|
382
440
|
/**
|
|
383
441
|
* Storages
|
|
384
442
|
*/
|
|
@@ -388,37 +446,33 @@ export interface IStorageBase<
|
|
|
388
446
|
TSegmentsCache extends ISegmentsCacheBase,
|
|
389
447
|
TImpressionsCache extends IImpressionsCacheBase,
|
|
390
448
|
TEventsCache extends IEventsCacheBase,
|
|
391
|
-
|
|
392
|
-
TCountsCache extends ICountsCacheSync | ICountsCacheAsync,
|
|
449
|
+
TTelemetryCache extends ITelemetryCacheSync | ITelemetryCacheAsync
|
|
393
450
|
> {
|
|
394
451
|
splits: TSplitsCache,
|
|
395
452
|
segments: TSegmentsCache,
|
|
396
453
|
impressions: TImpressionsCache,
|
|
397
454
|
impressionCounts?: IImpressionCountsCacheSync,
|
|
398
455
|
events: TEventsCache,
|
|
399
|
-
|
|
400
|
-
counts?: TCountsCache,
|
|
456
|
+
telemetry?: TTelemetryCache
|
|
401
457
|
destroy(): void | Promise<void>,
|
|
402
458
|
shared?: (matchingKey: string, onReadyCb: (error?: any) => void) => this
|
|
403
459
|
}
|
|
404
460
|
|
|
405
|
-
export
|
|
461
|
+
export interface IStorageSync extends IStorageBase<
|
|
406
462
|
ISplitsCacheSync,
|
|
407
463
|
ISegmentsCacheSync,
|
|
408
464
|
IImpressionsCacheSync,
|
|
409
465
|
IEventsCacheSync,
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
>
|
|
466
|
+
ITelemetryCacheSync
|
|
467
|
+
> { }
|
|
413
468
|
|
|
414
|
-
export
|
|
469
|
+
export interface IStorageAsync extends IStorageBase<
|
|
415
470
|
ISplitsCacheAsync,
|
|
416
471
|
ISegmentsCacheAsync,
|
|
417
472
|
IImpressionsCacheAsync | IImpressionsCacheSync,
|
|
418
473
|
IEventsCacheAsync | IEventsCacheSync,
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
>
|
|
474
|
+
ITelemetryCacheAsync
|
|
475
|
+
> { }
|
|
422
476
|
|
|
423
477
|
/** StorageFactory */
|
|
424
478
|
|
|
@@ -429,14 +483,12 @@ export interface IStorageFactoryParams {
|
|
|
429
483
|
impressionsQueueSize?: number,
|
|
430
484
|
eventsQueueSize?: number,
|
|
431
485
|
optimize?: boolean /* whether create the `impressionCounts` cache (OPTIMIZED impression mode) or not (DEBUG impression mode) */,
|
|
486
|
+
mode: SDKMode,
|
|
432
487
|
|
|
433
488
|
// ATM, only used by InLocalStorage
|
|
434
489
|
matchingKey?: string, /* undefined on server-side SDKs */
|
|
435
490
|
splitFiltersValidation?: ISplitFiltersValidation,
|
|
436
491
|
|
|
437
|
-
// ATM, only used by PluggableStorage
|
|
438
|
-
mode?: SDKMode,
|
|
439
|
-
|
|
440
492
|
// This callback is invoked when the storage is ready to be used. Error-first callback style: if an error is passed,
|
|
441
493
|
// it means that the storge fail to connect and shouldn't be used.
|
|
442
494
|
// It is meant for emitting SDK_READY event in consumer mode, and for synchronizer to wait before using the storage.
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { ISyncManager, ISyncManagerCS
|
|
1
|
+
import { ISyncManager, ISyncManagerCS } from '../types';
|
|
2
2
|
import { fromObjectSyncTaskFactory } from './syncTasks/fromObjectSyncTask';
|
|
3
3
|
import { objectAssign } from '../../utils/lang/objectAssign';
|
|
4
4
|
import { ISplitsParser } from './splitsParser/types';
|
|
5
5
|
import { IReadinessManager } from '../../readiness/types';
|
|
6
6
|
import { SDK_SEGMENTS_ARRIVED } from '../../readiness/constants';
|
|
7
|
+
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
7
8
|
|
|
8
9
|
function flush() {
|
|
9
10
|
return Promise.resolve();
|
|
@@ -17,7 +18,7 @@ function flush() {
|
|
|
17
18
|
*/
|
|
18
19
|
export function syncManagerOfflineFactory(
|
|
19
20
|
splitsParserFactory: () => ISplitsParser
|
|
20
|
-
): (params:
|
|
21
|
+
): (params: ISdkFactoryContextSync) => ISyncManagerCS {
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* SyncManager factory for modular SDK
|
|
@@ -26,7 +27,7 @@ export function syncManagerOfflineFactory(
|
|
|
26
27
|
settings,
|
|
27
28
|
readiness,
|
|
28
29
|
storage,
|
|
29
|
-
}:
|
|
30
|
+
}: ISdkFactoryContextSync): ISyncManagerCS {
|
|
30
31
|
|
|
31
32
|
return objectAssign(
|
|
32
33
|
fromObjectSyncTaskFactory(splitsParserFactory(), storage, readiness, settings),
|
|
@@ -7,20 +7,20 @@ 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
9
|
import { POLLING_SMART_PAUSING, POLLING_START, POLLING_STOP } from '../../logger/constants';
|
|
10
|
-
import {
|
|
10
|
+
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Expose start / stop mechanism for polling data from services.
|
|
14
14
|
* For client-side API with multiple clients.
|
|
15
15
|
*/
|
|
16
16
|
export function pollingManagerCSFactory(
|
|
17
|
-
params:
|
|
17
|
+
params: ISdkFactoryContextSync
|
|
18
18
|
): IPollingManagerCS {
|
|
19
19
|
|
|
20
20
|
const { splitApi, storage, readiness, settings } = params;
|
|
21
21
|
const log = settings.log;
|
|
22
22
|
|
|
23
|
-
const splitsSyncTask: ISplitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings);
|
|
23
|
+
const splitsSyncTask: ISplitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings, true);
|
|
24
24
|
|
|
25
25
|
// Map of matching keys to their corresponding MySegmentsSyncTask.
|
|
26
26
|
const mySegmentsSyncTasks: Record<string, ISegmentsSyncTask> = {};
|
|
@@ -3,13 +3,13 @@ import { segmentsSyncTaskFactory } from './syncTasks/segmentsSyncTask';
|
|
|
3
3
|
import { IPollingManager, ISegmentsSyncTask, ISplitsSyncTask } from './types';
|
|
4
4
|
import { thenable } from '../../utils/promise/thenable';
|
|
5
5
|
import { POLLING_START, POLLING_STOP, LOG_PREFIX_SYNC_POLLING } from '../../logger/constants';
|
|
6
|
-
import {
|
|
6
|
+
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Expose start / stop mechanism for pulling data from services.
|
|
10
10
|
*/
|
|
11
11
|
export function pollingManagerSSFactory(
|
|
12
|
-
params:
|
|
12
|
+
params: ISdkFactoryContextSync
|
|
13
13
|
): IPollingManager {
|
|
14
14
|
|
|
15
15
|
const { splitApi, storage, readiness, settings } = params;
|
|
@@ -15,6 +15,7 @@ export function splitsSyncTaskFactory(
|
|
|
15
15
|
storage: IStorageSync,
|
|
16
16
|
readiness: IReadinessManager,
|
|
17
17
|
settings: ISettings,
|
|
18
|
+
isClientSide?: boolean
|
|
18
19
|
): ISplitsSyncTask {
|
|
19
20
|
return syncTaskFactory(
|
|
20
21
|
settings.log,
|
|
@@ -26,6 +27,7 @@ export function splitsSyncTaskFactory(
|
|
|
26
27
|
readiness.splits,
|
|
27
28
|
settings.startup.requestTimeoutBeforeReady,
|
|
28
29
|
settings.startup.retriesOnFailureBeforeReady,
|
|
30
|
+
isClientSide
|
|
29
31
|
),
|
|
30
32
|
settings.scheduler.featuresRefreshRate,
|
|
31
33
|
'splitChangesUpdater',
|
|
@@ -33,10 +33,6 @@ export function mySegmentsUpdaterFactory(
|
|
|
33
33
|
function _promiseDecorator<T>(promise: Promise<T>) {
|
|
34
34
|
if (startingUp) promise = timeout(requestTimeoutBeforeReady, promise);
|
|
35
35
|
return promise;
|
|
36
|
-
|
|
37
|
-
// @TODO telemetry
|
|
38
|
-
// NOTE: We only collect metrics on startup.
|
|
39
|
-
// mySegmentsPromise = tracker.start(tracker.TaskNames.MY_SEGMENTS_FETCH, startingUp ? metricCollectors : false, mySegmentsPromise);
|
|
40
36
|
}
|
|
41
37
|
|
|
42
38
|
// @TODO if allowing pluggable storages, handle async execution
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ISegmentChangesFetcher } from '../fetchers/types';
|
|
2
2
|
import { ISegmentsCacheBase } from '../../../storages/types';
|
|
3
3
|
import { IReadinessManager } from '../../../readiness/types';
|
|
4
|
-
import {
|
|
4
|
+
import { MaybeThenable } from '../../../dtos/types';
|
|
5
5
|
import { findIndex } from '../../../utils/lang';
|
|
6
6
|
import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
|
|
7
7
|
import { ILogger } from '../../../logger/types';
|
|
@@ -30,14 +30,6 @@ export function segmentChangesUpdaterFactory(
|
|
|
30
30
|
|
|
31
31
|
let readyOnAlreadyExistentState = true;
|
|
32
32
|
|
|
33
|
-
/** telemetry decorator for `segmentChangesFetcher` promise */
|
|
34
|
-
function _promiseDecorator(promise: Promise<ISegmentChangesResponse[]>) {
|
|
35
|
-
return promise;
|
|
36
|
-
// @TODO handle telemetry?
|
|
37
|
-
// const collectMetrics = startingUp || isNode; // If we are on the browser, only collect this metric for first fetch. On node do it always.
|
|
38
|
-
// splitsPromise = tracker.start(tracker.TaskNames.SPLITS_FETCH, collectMetrics ? metricCollectors : false, splitsPromise);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
33
|
/**
|
|
42
34
|
* Segments updater returns a promise that resolves with a `false` boolean value if it fails at least to fetch a segment or synchronize it with the storage.
|
|
43
35
|
* Thus, a false result doesn't imply that SDK_SEGMENTS_ARRIVED was not emitted.
|
|
@@ -67,7 +59,7 @@ export function segmentChangesUpdaterFactory(
|
|
|
67
59
|
// if fetchOnlyNew flag, avoid processing already fetched segments
|
|
68
60
|
if (fetchOnlyNew && since !== -1) return -1;
|
|
69
61
|
|
|
70
|
-
return segmentChangesFetcher(since, segmentName, noCache
|
|
62
|
+
return segmentChangesFetcher(since, segmentName, noCache).then(function (changes) {
|
|
71
63
|
let changeNumber = -1;
|
|
72
64
|
const results: MaybeThenable<boolean | void>[] = [];
|
|
73
65
|
changes.forEach(x => {
|
|
@@ -93,18 +93,15 @@ export function splitChangesUpdaterFactory(
|
|
|
93
93
|
splitsEventEmitter?: ISplitsEventEmitter,
|
|
94
94
|
requestTimeoutBeforeReady: number = 0,
|
|
95
95
|
retriesOnFailureBeforeReady: number = 0,
|
|
96
|
+
isClientSide?: boolean
|
|
96
97
|
): ISplitChangesUpdater {
|
|
97
98
|
|
|
98
99
|
let startingUp = true;
|
|
99
100
|
|
|
100
|
-
/** timeout
|
|
101
|
+
/** timeout decorator for `splitChangesFetcher` promise */
|
|
101
102
|
function _promiseDecorator<T>(promise: Promise<T>) {
|
|
102
103
|
if (startingUp && requestTimeoutBeforeReady) promise = timeout(requestTimeoutBeforeReady, promise);
|
|
103
104
|
return promise;
|
|
104
|
-
|
|
105
|
-
// @TODO telemetry
|
|
106
|
-
// const collectMetrics = startingUp || isNode; // If we are on the browser, only collect this metric for first fetch. On node do it always.
|
|
107
|
-
// splitsPromise = tracker.start(tracker.TaskNames.SPLITS_FETCH, collectMetrics ? metricCollectors : false, splitsPromise);
|
|
108
105
|
}
|
|
109
106
|
|
|
110
107
|
/**
|
|
@@ -144,7 +141,7 @@ export function splitChangesUpdaterFactory(
|
|
|
144
141
|
|
|
145
142
|
if (splitsEventEmitter) {
|
|
146
143
|
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
147
|
-
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && checkAllSegmentsExist(segments)))
|
|
144
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && (isClientSide || checkAllSegmentsExist(segments))))
|
|
148
145
|
.catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
149
146
|
.then(emitSplitsArrivedEvent => {
|
|
150
147
|
// emit SDK events
|