@splitsoftware/splitio-commons 1.3.1 → 1.3.2-rc.2

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.
Files changed (219) hide show
  1. package/cjs/consent/sdkUserConsent.js +1 -1
  2. package/cjs/listeners/browser.js +5 -4
  3. package/cjs/logger/constants.js +2 -1
  4. package/cjs/logger/messages/error.js +2 -1
  5. package/cjs/logger/messages/info.js +3 -3
  6. package/cjs/logger/messages/warn.js +2 -2
  7. package/cjs/sdkClient/client.js +17 -3
  8. package/cjs/sdkClient/sdkClient.js +4 -1
  9. package/cjs/sdkFactory/index.js +16 -19
  10. package/cjs/services/splitApi.js +15 -14
  11. package/cjs/services/splitHttpClient.js +4 -1
  12. package/cjs/storages/AbstractSegmentsCacheSync.js +0 -5
  13. package/cjs/storages/KeyBuilderSS.js +12 -19
  14. package/cjs/storages/findLatencyIndex.js +11 -6
  15. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +13 -1
  16. package/cjs/storages/inLocalStorage/index.js +4 -1
  17. package/cjs/storages/inMemory/InMemoryStorage.js +2 -0
  18. package/cjs/storages/inMemory/InMemoryStorageCS.js +3 -0
  19. package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +6 -0
  20. package/cjs/storages/inMemory/SegmentsCacheInMemory.js +6 -0
  21. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +165 -0
  22. package/cjs/storages/inRedis/TelemetryCacheInRedis.js +29 -0
  23. package/cjs/storages/inRedis/index.js +2 -4
  24. package/cjs/storages/pluggable/TelemetryCachePluggable.js +27 -0
  25. package/cjs/storages/pluggable/index.js +2 -1
  26. package/cjs/sync/polling/pollingManagerCS.js +1 -1
  27. package/cjs/sync/polling/syncTasks/splitsSyncTask.js +2 -2
  28. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +0 -3
  29. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -8
  30. package/cjs/sync/polling/updaters/splitChangesUpdater.js +3 -6
  31. package/cjs/sync/streaming/SSEHandler/NotificationKeeper.js +20 -13
  32. package/cjs/sync/streaming/SSEHandler/index.js +21 -15
  33. package/cjs/sync/streaming/pushManager.js +7 -4
  34. package/cjs/sync/submitters/eventsSubmitter.js +28 -0
  35. package/cjs/sync/submitters/{impressionCountsSyncTask.js → impressionCountsSubmitter.js} +10 -7
  36. package/cjs/sync/submitters/{impressionsSyncTask.js → impressionsSubmitter.js} +8 -8
  37. package/cjs/sync/submitters/submitter.js +66 -0
  38. package/cjs/sync/submitters/submitterManager.js +12 -10
  39. package/cjs/sync/submitters/telemetrySubmitter.js +128 -0
  40. package/cjs/sync/syncManagerOnline.js +6 -2
  41. package/cjs/trackers/eventTracker.js +5 -1
  42. package/cjs/trackers/impressionsTracker.js +9 -1
  43. package/cjs/trackers/telemetryTracker.js +65 -0
  44. package/cjs/utils/constants/index.js +40 -1
  45. package/cjs/utils/inputValidation/apiKey.js +12 -11
  46. package/cjs/utils/settingsValidation/index.js +35 -11
  47. package/cjs/utils/settingsValidation/url.js +4 -0
  48. package/cjs/utils/timeTracker/index.js +1 -0
  49. package/cjs/utils/timeTracker/timer.js +2 -2
  50. package/esm/consent/sdkUserConsent.js +1 -1
  51. package/esm/listeners/browser.js +3 -2
  52. package/esm/logger/constants.js +1 -0
  53. package/esm/logger/messages/error.js +2 -1
  54. package/esm/logger/messages/info.js +3 -3
  55. package/esm/logger/messages/warn.js +2 -2
  56. package/esm/sdkClient/client.js +18 -4
  57. package/esm/sdkClient/sdkClient.js +4 -1
  58. package/esm/sdkFactory/index.js +16 -19
  59. package/esm/services/splitApi.js +15 -14
  60. package/esm/services/splitHttpClient.js +4 -1
  61. package/esm/storages/AbstractSegmentsCacheSync.js +0 -5
  62. package/esm/storages/KeyBuilderSS.js +12 -19
  63. package/esm/storages/findLatencyIndex.js +11 -6
  64. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +13 -1
  65. package/esm/storages/inLocalStorage/index.js +5 -2
  66. package/esm/storages/inMemory/InMemoryStorage.js +3 -1
  67. package/esm/storages/inMemory/InMemoryStorageCS.js +4 -1
  68. package/esm/storages/inMemory/MySegmentsCacheInMemory.js +6 -0
  69. package/esm/storages/inMemory/SegmentsCacheInMemory.js +6 -0
  70. package/esm/storages/inMemory/TelemetryCacheInMemory.js +161 -0
  71. package/esm/storages/inRedis/TelemetryCacheInRedis.js +26 -0
  72. package/esm/storages/inRedis/index.js +2 -4
  73. package/esm/storages/pluggable/TelemetryCachePluggable.js +24 -0
  74. package/esm/storages/pluggable/index.js +2 -1
  75. package/esm/sync/polling/pollingManagerCS.js +1 -1
  76. package/esm/sync/polling/syncTasks/splitsSyncTask.js +2 -2
  77. package/esm/sync/polling/updaters/mySegmentsUpdater.js +0 -3
  78. package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -8
  79. package/esm/sync/polling/updaters/splitChangesUpdater.js +3 -6
  80. package/esm/sync/streaming/SSEHandler/NotificationKeeper.js +8 -1
  81. package/esm/sync/streaming/SSEHandler/index.js +21 -15
  82. package/esm/sync/streaming/pushManager.js +7 -4
  83. package/esm/sync/submitters/eventsSubmitter.js +24 -0
  84. package/esm/sync/submitters/{impressionCountsSyncTask.js → impressionCountsSubmitter.js} +8 -5
  85. package/esm/sync/submitters/{impressionsSyncTask.js → impressionsSubmitter.js} +6 -6
  86. package/esm/sync/submitters/submitter.js +61 -0
  87. package/esm/sync/submitters/submitterManager.js +12 -10
  88. package/esm/sync/submitters/telemetrySubmitter.js +122 -0
  89. package/esm/sync/syncManagerOnline.js +6 -2
  90. package/esm/trackers/eventTracker.js +6 -2
  91. package/esm/trackers/impressionsTracker.js +10 -2
  92. package/esm/trackers/telemetryTracker.js +61 -0
  93. package/esm/utils/constants/index.js +38 -0
  94. package/esm/utils/inputValidation/apiKey.js +2 -1
  95. package/esm/utils/settingsValidation/index.js +34 -10
  96. package/esm/utils/settingsValidation/url.js +4 -0
  97. package/esm/utils/timeTracker/index.js +1 -0
  98. package/esm/utils/timeTracker/timer.js +2 -2
  99. package/package.json +1 -1
  100. package/src/consent/sdkUserConsent.ts +1 -1
  101. package/src/listeners/browser.ts +3 -2
  102. package/src/logger/constants.ts +1 -0
  103. package/src/logger/messages/error.ts +2 -1
  104. package/src/logger/messages/info.ts +3 -3
  105. package/src/logger/messages/warn.ts +2 -2
  106. package/src/sdkClient/client.ts +23 -4
  107. package/src/sdkClient/sdkClient.ts +4 -1
  108. package/src/sdkFactory/index.ts +22 -24
  109. package/src/sdkFactory/types.ts +32 -15
  110. package/src/services/splitApi.ts +17 -14
  111. package/src/services/splitHttpClient.ts +6 -3
  112. package/src/services/types.ts +7 -5
  113. package/src/storages/AbstractSegmentsCacheSync.ts +8 -3
  114. package/src/storages/KeyBuilderSS.ts +13 -50
  115. package/src/storages/findLatencyIndex.ts +12 -3
  116. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +13 -1
  117. package/src/storages/inLocalStorage/index.ts +5 -2
  118. package/src/storages/inMemory/InMemoryStorage.ts +3 -1
  119. package/src/storages/inMemory/InMemoryStorageCS.ts +4 -1
  120. package/src/storages/inMemory/MySegmentsCacheInMemory.ts +8 -0
  121. package/src/storages/inMemory/SegmentsCacheInMemory.ts +6 -0
  122. package/src/storages/inMemory/TelemetryCacheInMemory.ts +210 -0
  123. package/src/storages/inRedis/TelemetryCacheInRedis.ts +29 -0
  124. package/src/storages/inRedis/index.ts +2 -4
  125. package/src/storages/pluggable/TelemetryCachePluggable.ts +26 -0
  126. package/src/storages/pluggable/index.ts +2 -1
  127. package/src/storages/types.ts +84 -32
  128. package/src/sync/offline/syncManagerOffline.ts +4 -3
  129. package/src/sync/polling/pollingManagerCS.ts +3 -3
  130. package/src/sync/polling/pollingManagerSS.ts +2 -2
  131. package/src/sync/polling/syncTasks/splitsSyncTask.ts +2 -0
  132. package/src/sync/polling/updaters/mySegmentsUpdater.ts +0 -4
  133. package/src/sync/polling/updaters/segmentChangesUpdater.ts +2 -10
  134. package/src/sync/polling/updaters/splitChangesUpdater.ts +3 -6
  135. package/src/sync/streaming/SSEHandler/NotificationKeeper.ts +11 -1
  136. package/src/sync/streaming/SSEHandler/index.ts +21 -14
  137. package/src/sync/streaming/pushManager.ts +11 -7
  138. package/src/sync/submitters/eventsSubmitter.ts +35 -0
  139. package/src/sync/submitters/{impressionCountsSyncTask.ts → impressionCountsSubmitter.ts} +15 -15
  140. package/src/sync/submitters/{impressionsSyncTask.ts → impressionsSubmitter.ts} +12 -16
  141. package/src/sync/submitters/{submitterSyncTask.ts → submitter.ts} +34 -16
  142. package/src/sync/submitters/submitterManager.ts +14 -11
  143. package/src/sync/submitters/telemetrySubmitter.ts +143 -0
  144. package/src/sync/submitters/types.ts +123 -0
  145. package/src/sync/syncManagerOnline.ts +13 -7
  146. package/src/sync/types.ts +0 -15
  147. package/src/trackers/eventTracker.ts +7 -3
  148. package/src/trackers/impressionsTracker.ts +11 -3
  149. package/src/trackers/telemetryTracker.ts +63 -0
  150. package/src/trackers/types.ts +24 -0
  151. package/src/types.ts +35 -6
  152. package/src/utils/constants/index.ts +45 -0
  153. package/src/utils/inputValidation/apiKey.ts +2 -1
  154. package/src/utils/settingsValidation/index.ts +35 -11
  155. package/src/utils/settingsValidation/url.ts +4 -0
  156. package/src/utils/timeTracker/index.ts +1 -1
  157. package/src/utils/timeTracker/timer.ts +3 -3
  158. package/types/logger/constants.d.ts +1 -0
  159. package/types/sdkFactory/types.d.ts +29 -14
  160. package/types/services/splitApi.d.ts +2 -1
  161. package/types/services/types.d.ts +8 -5
  162. package/types/storages/AbstractSegmentsCacheSync.d.ts +7 -3
  163. package/types/storages/KeyBuilderSS.d.ts +3 -3
  164. package/types/storages/findLatencyIndex.d.ts +7 -1
  165. package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +2 -0
  166. package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +2 -0
  167. package/types/storages/inMemory/SegmentsCacheInMemory.d.ts +1 -0
  168. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -2
  169. package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +3 -3
  170. package/types/storages/pluggable/TelemetryCachePluggable.d.ts +2 -2
  171. package/types/storages/types.d.ts +71 -22
  172. package/types/sync/offline/syncManagerOffline.d.ts +3 -2
  173. package/types/sync/polling/pollingManagerCS.d.ts +2 -2
  174. package/types/sync/polling/pollingManagerSS.d.ts +2 -2
  175. package/types/sync/polling/syncTasks/splitsSyncTask.d.ts +1 -1
  176. package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -1
  177. package/types/sync/streaming/SSEHandler/NotificationKeeper.d.ts +2 -1
  178. package/types/sync/streaming/SSEHandler/index.d.ts +2 -1
  179. package/types/sync/streaming/pushManager.d.ts +2 -2
  180. package/types/sync/submitters/eventsSubmitter.d.ts +5 -0
  181. package/types/sync/submitters/impressionCountsSubmitter.d.ts +10 -0
  182. package/types/sync/submitters/impressionsSubmitter.d.ts +11 -0
  183. package/types/sync/submitters/submitter.d.ts +12 -0
  184. package/types/sync/submitters/submitterManager.d.ts +2 -2
  185. package/types/sync/submitters/telemetrySubmitter.d.ts +24 -0
  186. package/types/sync/submitters/telemetrySyncTask.d.ts +0 -27
  187. package/types/sync/submitters/types.d.ts +107 -0
  188. package/types/sync/syncManagerOnline.d.ts +3 -2
  189. package/types/sync/types.d.ts +0 -13
  190. package/types/trackers/eventTracker.d.ts +2 -2
  191. package/types/trackers/impressionsTracker.d.ts +2 -2
  192. package/types/trackers/telemetryTracker.d.ts +2 -3
  193. package/types/trackers/types.d.ts +22 -0
  194. package/types/types.d.ts +33 -4
  195. package/types/utils/constants/index.d.ts +37 -0
  196. package/types/utils/inputValidation/apiKey.d.ts +1 -0
  197. package/types/utils/settingsValidation/index.d.ts +40 -0
  198. package/types/utils/timeTracker/index.d.ts +1 -1
  199. package/types/utils/timeTracker/timer.d.ts +1 -1
  200. package/cjs/storages/inMemory/CountsCacheInMemory.js +0 -38
  201. package/cjs/storages/inMemory/LatenciesCacheInMemory.js +0 -43
  202. package/cjs/storages/inRedis/CountsCacheInRedis.js +0 -16
  203. package/cjs/storages/inRedis/LatenciesCacheInRedis.js +0 -18
  204. package/cjs/sync/submitters/eventsSyncTask.js +0 -44
  205. package/cjs/sync/submitters/metricsSyncTask.js +0 -31
  206. package/cjs/sync/submitters/submitterSyncTask.js +0 -44
  207. package/esm/storages/inMemory/CountsCacheInMemory.js +0 -35
  208. package/esm/storages/inMemory/LatenciesCacheInMemory.js +0 -40
  209. package/esm/storages/inRedis/CountsCacheInRedis.js +0 -13
  210. package/esm/storages/inRedis/LatenciesCacheInRedis.js +0 -15
  211. package/esm/sync/submitters/eventsSyncTask.js +0 -40
  212. package/esm/sync/submitters/metricsSyncTask.js +0 -26
  213. package/esm/sync/submitters/submitterSyncTask.js +0 -40
  214. package/src/storages/inMemory/CountsCacheInMemory.ts +0 -37
  215. package/src/storages/inMemory/LatenciesCacheInMemory.ts +0 -45
  216. package/src/storages/inRedis/CountsCacheInRedis.ts +0 -20
  217. package/src/storages/inRedis/LatenciesCacheInRedis.ts +0 -23
  218. package/src/sync/submitters/eventsSyncTask.ts +0 -57
  219. package/src/sync/submitters/metricsSyncTask.ts +0 -49
@@ -0,0 +1,161 @@
1
+ import { findLatencyIndex } from '../findLatencyIndex';
2
+ var MAX_STREAMING_EVENTS = 20;
3
+ var MAX_TAGS = 10;
4
+ function newBuckets() {
5
+ // MAX_LATENCY_BUCKET_COUNT (length) is 23;
6
+ return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
7
+ }
8
+ var ACCEPTANCE_RANGE = 0.001;
9
+ /**
10
+ * Used on client-side. 0.1% of instances will track telemetry
11
+ */
12
+ export function shouldRecordTelemetry() {
13
+ return Math.random() <= ACCEPTANCE_RANGE;
14
+ }
15
+ var TelemetryCacheInMemory = /** @class */ (function () {
16
+ function TelemetryCacheInMemory() {
17
+ this.notReadyUsage = 0;
18
+ this.impressionStats = [0, 0, 0];
19
+ this.eventStats = [0, 0];
20
+ // @ts-expect-error
21
+ this.lastSync = {};
22
+ // @ts-expect-error
23
+ this.httpErrors = {};
24
+ // @ts-expect-error
25
+ this.httpLatencies = {};
26
+ this.authRejections = 0;
27
+ this.tokenRefreshes = 0;
28
+ this.streamingEvents = [];
29
+ this.tags = [];
30
+ // @ts-expect-error
31
+ this.exceptions = {};
32
+ // @ts-expect-error
33
+ this.latencies = {};
34
+ }
35
+ TelemetryCacheInMemory.prototype.getTimeUntilReady = function () {
36
+ return this.timeUntilReady;
37
+ };
38
+ TelemetryCacheInMemory.prototype.recordTimeUntilReady = function (ms) {
39
+ this.timeUntilReady = ms;
40
+ };
41
+ TelemetryCacheInMemory.prototype.getTimeUntilReadyFromCache = function () {
42
+ return this.timeUntilReadyFromCache;
43
+ };
44
+ TelemetryCacheInMemory.prototype.recordTimeUntilReadyFromCache = function (ms) {
45
+ this.timeUntilReadyFromCache = ms;
46
+ };
47
+ TelemetryCacheInMemory.prototype.getNonReadyUsage = function () {
48
+ return this.notReadyUsage;
49
+ };
50
+ TelemetryCacheInMemory.prototype.recordNonReadyUsage = function () {
51
+ this.notReadyUsage++;
52
+ };
53
+ TelemetryCacheInMemory.prototype.getImpressionStats = function (type) {
54
+ return this.impressionStats[type];
55
+ };
56
+ TelemetryCacheInMemory.prototype.recordImpressionStats = function (type, count) {
57
+ this.impressionStats[type] += count;
58
+ };
59
+ TelemetryCacheInMemory.prototype.getEventStats = function (type) {
60
+ return this.eventStats[type];
61
+ };
62
+ TelemetryCacheInMemory.prototype.recordEventStats = function (type, count) {
63
+ this.eventStats[type] += count;
64
+ };
65
+ TelemetryCacheInMemory.prototype.getLastSynchronization = function () {
66
+ return this.lastSync;
67
+ };
68
+ TelemetryCacheInMemory.prototype.recordSuccessfulSync = function (resource, timeMs) {
69
+ this.lastSync[resource] = timeMs;
70
+ };
71
+ TelemetryCacheInMemory.prototype.popHttpErrors = function () {
72
+ var result = this.httpErrors; // @ts-expect-error
73
+ this.httpErrors = {};
74
+ return result;
75
+ };
76
+ TelemetryCacheInMemory.prototype.recordHttpError = function (resource, status) {
77
+ if (!this.httpErrors[resource])
78
+ this.httpErrors[resource] = {};
79
+ if (!this.httpErrors[resource][status]) {
80
+ this.httpErrors[resource][status] = 1;
81
+ }
82
+ else {
83
+ this.httpErrors[resource][status]++;
84
+ }
85
+ };
86
+ TelemetryCacheInMemory.prototype.popHttpLatencies = function () {
87
+ var result = this.httpLatencies; // @ts-expect-error
88
+ this.httpLatencies = {};
89
+ return result;
90
+ };
91
+ TelemetryCacheInMemory.prototype.recordHttpLatency = function (resource, latencyMs) {
92
+ if (!this.httpLatencies[resource]) {
93
+ this.httpLatencies[resource] = newBuckets();
94
+ }
95
+ this.httpLatencies[resource][findLatencyIndex(latencyMs)]++;
96
+ };
97
+ TelemetryCacheInMemory.prototype.popAuthRejections = function () {
98
+ var result = this.authRejections;
99
+ this.authRejections = 0;
100
+ return result;
101
+ };
102
+ TelemetryCacheInMemory.prototype.recordAuthRejections = function () {
103
+ this.authRejections++;
104
+ };
105
+ TelemetryCacheInMemory.prototype.popTokenRefreshes = function () {
106
+ var result = this.tokenRefreshes;
107
+ this.tokenRefreshes = 0;
108
+ return result;
109
+ };
110
+ TelemetryCacheInMemory.prototype.recordTokenRefreshes = function () {
111
+ this.tokenRefreshes++;
112
+ };
113
+ TelemetryCacheInMemory.prototype.popStreamingEvents = function () {
114
+ return this.streamingEvents.splice(0);
115
+ };
116
+ TelemetryCacheInMemory.prototype.recordStreamingEvents = function (streamingEvent) {
117
+ if (this.streamingEvents.length < MAX_STREAMING_EVENTS) {
118
+ this.streamingEvents.push(streamingEvent);
119
+ }
120
+ };
121
+ TelemetryCacheInMemory.prototype.popTags = function () {
122
+ return this.tags.splice(0);
123
+ };
124
+ TelemetryCacheInMemory.prototype.addTag = function (tag) {
125
+ if (this.tags.length < MAX_TAGS) {
126
+ this.tags.push(tag);
127
+ }
128
+ };
129
+ TelemetryCacheInMemory.prototype.getSessionLength = function () {
130
+ return this.sessionLength;
131
+ };
132
+ TelemetryCacheInMemory.prototype.recordSessionLength = function (ms) {
133
+ this.sessionLength = ms;
134
+ };
135
+ TelemetryCacheInMemory.prototype.popExceptions = function () {
136
+ var result = this.exceptions; // @ts-expect-error
137
+ this.exceptions = {};
138
+ return result;
139
+ };
140
+ TelemetryCacheInMemory.prototype.recordException = function (method) {
141
+ if (!this.exceptions[method]) {
142
+ this.exceptions[method] = 1;
143
+ }
144
+ else {
145
+ this.exceptions[method]++;
146
+ }
147
+ };
148
+ TelemetryCacheInMemory.prototype.popLatencies = function () {
149
+ var result = this.latencies; // @ts-expect-error
150
+ this.latencies = {};
151
+ return result;
152
+ };
153
+ TelemetryCacheInMemory.prototype.recordLatency = function (method, latencyMs) {
154
+ if (!this.latencies[method]) {
155
+ this.latencies[method] = newBuckets();
156
+ }
157
+ this.latencies[method][findLatencyIndex(latencyMs)]++;
158
+ };
159
+ return TelemetryCacheInMemory;
160
+ }());
161
+ export { TelemetryCacheInMemory };
@@ -0,0 +1,26 @@
1
+ import { findLatencyIndex } from '../findLatencyIndex';
2
+ var TelemetryCacheInRedis = /** @class */ (function () {
3
+ /**
4
+ * Create a Telemetry cache that uses Redis as storage.
5
+ * @param log Logger instance.
6
+ * @param keys Key builder.
7
+ * @param redis Redis client.
8
+ */
9
+ function TelemetryCacheInRedis(log, keys, redis) {
10
+ this.log = log;
11
+ this.keys = keys;
12
+ this.redis = redis;
13
+ }
14
+ TelemetryCacheInRedis.prototype.recordLatency = function (method, latencyMs) {
15
+ var _a = this.keys.buildLatencyKey(method, findLatencyIndex(latencyMs)).split('::'), key = _a[0], field = _a[1];
16
+ return this.redis.hincrby(key, field, 1)
17
+ .catch(function () { });
18
+ };
19
+ TelemetryCacheInRedis.prototype.recordException = function (method) {
20
+ var _a = this.keys.buildExceptionKey(method).split('::'), key = _a[0], field = _a[1];
21
+ return this.redis.hincrby(key, field, 1)
22
+ .catch(function () { });
23
+ };
24
+ return TelemetryCacheInRedis;
25
+ }());
26
+ export { TelemetryCacheInRedis };
@@ -5,9 +5,8 @@ import { SplitsCacheInRedis } from './SplitsCacheInRedis';
5
5
  import { SegmentsCacheInRedis } from './SegmentsCacheInRedis';
6
6
  import { ImpressionsCacheInRedis } from './ImpressionsCacheInRedis';
7
7
  import { EventsCacheInRedis } from './EventsCacheInRedis';
8
- import { LatenciesCacheInRedis } from './LatenciesCacheInRedis';
9
- import { CountsCacheInRedis } from './CountsCacheInRedis';
10
8
  import { STORAGE_REDIS } from '../../utils/constants';
9
+ import { TelemetryCacheInRedis } from './TelemetryCacheInRedis';
11
10
  /**
12
11
  * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.
13
12
  * @see {@link https://www.npmjs.com/package/ioredis}
@@ -28,8 +27,7 @@ export function InRedisStorage(options) {
28
27
  segments: new SegmentsCacheInRedis(log, keys, redisClient),
29
28
  impressions: new ImpressionsCacheInRedis(log, keys.buildImpressionsKey(), redisClient, metadata),
30
29
  events: new EventsCacheInRedis(log, keys.buildEventsKey(), redisClient, metadata),
31
- latencies: new LatenciesCacheInRedis(keys, redisClient),
32
- counts: new CountsCacheInRedis(keys, redisClient),
30
+ telemetry: new TelemetryCacheInRedis(log, keys, redisClient),
33
31
  // When using REDIS we should:
34
32
  // 1- Disconnect from the storage
35
33
  destroy: function () {
@@ -0,0 +1,24 @@
1
+ import { findLatencyIndex } from '../findLatencyIndex';
2
+ var TelemetryCachePluggable = /** @class */ (function () {
3
+ /**
4
+ * Create a Telemetry cache that uses a storage wrapper.
5
+ * @param log Logger instance.
6
+ * @param keys Key builder.
7
+ * @param wrapper Adapted wrapper storage.
8
+ */
9
+ function TelemetryCachePluggable(log, keys, wrapper) {
10
+ this.log = log;
11
+ this.keys = keys;
12
+ this.wrapper = wrapper;
13
+ }
14
+ TelemetryCachePluggable.prototype.recordLatency = function (method, latencyMs) {
15
+ return this.wrapper.incr(this.keys.buildLatencyKey(method, findLatencyIndex(latencyMs)))
16
+ .catch(function () { });
17
+ };
18
+ TelemetryCachePluggable.prototype.recordException = function (method) {
19
+ return this.wrapper.incr(this.keys.buildExceptionKey(method))
20
+ .catch(function () { });
21
+ };
22
+ return TelemetryCachePluggable;
23
+ }());
24
+ export { TelemetryCachePluggable };
@@ -63,7 +63,8 @@ export function PluggableStorage(options) {
63
63
  impressions: isPartialConsumer ? new ImpressionsCacheInMemory(impressionsQueueSize) : new ImpressionsCachePluggable(log, keys.buildImpressionsKey(), wrapper, metadata),
64
64
  impressionCounts: optimize ? new ImpressionCountsCacheInMemory() : undefined,
65
65
  events: isPartialConsumer ? promisifyEventsTrack(new EventsCacheInMemory(eventsQueueSize)) : new EventsCachePluggable(log, keys.buildEventsKey(), wrapper, metadata),
66
- // @TODO add telemetry cache when required
66
+ // @TODO Not using TelemetryCachePluggable yet, because it is not supported by the Split Synchronizer
67
+ // telemetry: isPartialConsumer ? new TelemetryCacheInMemory() : new TelemetryCachePluggable(log, keys, wrapper),
67
68
  // Disconnect the underlying storage
68
69
  destroy: function () {
69
70
  return wrapper.disconnect();
@@ -11,7 +11,7 @@ import { POLLING_SMART_PAUSING, POLLING_START, POLLING_STOP } from '../../logger
11
11
  export function pollingManagerCSFactory(params) {
12
12
  var splitApi = params.splitApi, storage = params.storage, readiness = params.readiness, settings = params.settings;
13
13
  var log = settings.log;
14
- var splitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings);
14
+ var splitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings, true);
15
15
  // Map of matching keys to their corresponding MySegmentsSyncTask.
16
16
  var mySegmentsSyncTasks = {};
17
17
  var matchingKey = getMatching(settings.core.key);
@@ -4,6 +4,6 @@ import { splitChangesUpdaterFactory } from '../updaters/splitChangesUpdater';
4
4
  /**
5
5
  * Creates a sync task that periodically executes a `splitChangesUpdater` task
6
6
  */
7
- export function splitsSyncTaskFactory(fetchSplitChanges, storage, readiness, settings) {
8
- return syncTaskFactory(settings.log, splitChangesUpdaterFactory(settings.log, splitChangesFetcherFactory(fetchSplitChanges), storage.splits, storage.segments, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
7
+ export function splitsSyncTaskFactory(fetchSplitChanges, storage, readiness, settings, isClientSide) {
8
+ return syncTaskFactory(settings.log, splitChangesUpdaterFactory(settings.log, splitChangesFetcherFactory(fetchSplitChanges), storage.splits, storage.segments, readiness.splits, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'splitChangesUpdater');
9
9
  }
@@ -15,9 +15,6 @@ export function mySegmentsUpdaterFactory(log, mySegmentsFetcher, splitsCache, my
15
15
  if (startingUp)
16
16
  promise = timeout(requestTimeoutBeforeReady, promise);
17
17
  return promise;
18
- // @TODO telemetry
19
- // NOTE: We only collect metrics on startup.
20
- // mySegmentsPromise = tracker.start(tracker.TaskNames.MY_SEGMENTS_FETCH, startingUp ? metricCollectors : false, mySegmentsPromise);
21
18
  }
22
19
  // @TODO if allowing pluggable storages, handle async execution
23
20
  function updateSegments(segmentsData) {
@@ -15,13 +15,6 @@ import { thenable } from '../../../utils/promise/thenable';
15
15
  */
16
16
  export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, readiness) {
17
17
  var readyOnAlreadyExistentState = true;
18
- /** telemetry decorator for `segmentChangesFetcher` promise */
19
- function _promiseDecorator(promise) {
20
- return promise;
21
- // @TODO handle telemetry?
22
- // const collectMetrics = startingUp || isNode; // If we are on the browser, only collect this metric for first fetch. On node do it always.
23
- // splitsPromise = tracker.start(tracker.TaskNames.SPLITS_FETCH, collectMetrics ? metricCollectors : false, splitsPromise);
24
- }
25
18
  /**
26
19
  * 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.
27
20
  * Thus, a false result doesn't imply that SDK_SEGMENTS_ARRIVED was not emitted.
@@ -47,7 +40,7 @@ export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segment
47
40
  // if fetchOnlyNew flag, avoid processing already fetched segments
48
41
  if (fetchOnlyNew && since !== -1)
49
42
  return -1;
50
- return segmentChangesFetcher(since, segmentName, noCache, _promiseDecorator).then(function (changes) {
43
+ return segmentChangesFetcher(since, segmentName, noCache).then(function (changes) {
51
44
  var changeNumber = -1;
52
45
  var results = [];
53
46
  changes.forEach(function (x) {
@@ -64,18 +64,15 @@ export function computeSplitsMutation(entries) {
64
64
  * @param requestTimeoutBeforeReady How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
65
65
  * @param retriesOnFailureBeforeReady How many retries on `/splitChanges` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
66
66
  */
67
- export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady) {
67
+ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments, splitsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
68
68
  if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
69
69
  if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
70
70
  var startingUp = true;
71
- /** timeout and telemetry decorator for `splitChangesFetcher` promise */
71
+ /** timeout decorator for `splitChangesFetcher` promise */
72
72
  function _promiseDecorator(promise) {
73
73
  if (startingUp && requestTimeoutBeforeReady)
74
74
  promise = timeout(requestTimeoutBeforeReady, promise);
75
75
  return promise;
76
- // @TODO telemetry
77
- // const collectMetrics = startingUp || isNode; // If we are on the browser, only collect this metric for first fetch. On node do it always.
78
- // splitsPromise = tracker.start(tracker.TaskNames.SPLITS_FETCH, collectMetrics ? metricCollectors : false, splitsPromise);
79
76
  }
80
77
  /**
81
78
  * SplitChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch splits or synchronize them with the storage.
@@ -109,7 +106,7 @@ export function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, seg
109
106
  ]).then(function () {
110
107
  if (splitsEventEmitter) {
111
108
  // To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
112
- return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && checkAllSegmentsExist(segments)))
109
+ return Promise.resolve(!splitsEventEmitter.splitsArrived || (since !== splitChanges.till && (isClientSide || checkAllSegmentsExist(segments))))
113
110
  .catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
114
111
  .then(function (emitSplitsArrivedEvent) {
115
112
  // emit SDK events
@@ -1,12 +1,14 @@
1
+ import { CONNECTION_ESTABLISHED, DISABLED, ENABLED, OCCUPANCY_PRI, OCCUPANCY_SEC, PAUSED, STREAMING_STATUS } from '../../../utils/constants';
1
2
  import { ControlType, PUSH_SUBSYSTEM_UP, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN } from '../constants';
2
3
  var CONTROL_CHANNEL_REGEXS = [/control_pri$/, /control_sec$/];
4
+ var STREAMING_EVENT_TYPES = [OCCUPANCY_PRI, OCCUPANCY_SEC];
3
5
  /**
4
6
  * Factory of notification keeper, which process OCCUPANCY and CONTROL notifications and emits the corresponding push events.
5
7
  *
6
8
  * @param pushEmitter emitter for events related to streaming support
7
9
  */
8
10
  // @TODO update logic to handle OCCUPANCY for any region and rename according to new spec (e.g.: PUSH_SUBSYSTEM_UP --> PUSH_SUBSYSTEM_UP)
9
- export function notificationKeeperFactory(pushEmitter) {
11
+ export function notificationKeeperFactory(pushEmitter, telemetryTracker) {
10
12
  var channels = CONTROL_CHANNEL_REGEXS.map(function (regex) { return ({
11
13
  regex: regex,
12
14
  hasPublishers: true,
@@ -22,6 +24,7 @@ export function notificationKeeperFactory(pushEmitter) {
22
24
  }
23
25
  return {
24
26
  handleOpen: function () {
27
+ telemetryTracker.streamingEvent(CONNECTION_ESTABLISHED);
25
28
  pushEmitter.emit(PUSH_SUBSYSTEM_UP);
26
29
  },
27
30
  isStreamingUp: function () {
@@ -31,6 +34,7 @@ export function notificationKeeperFactory(pushEmitter) {
31
34
  for (var i = 0; i < channels.length; i++) {
32
35
  var c = channels[i];
33
36
  if (c.regex.test(channel)) {
37
+ telemetryTracker.streamingEvent(STREAMING_EVENT_TYPES[i], publishers);
34
38
  if (timestamp > c.oTime) {
35
39
  c.oTime = timestamp;
36
40
  c.hasPublishers = publishers !== 0;
@@ -65,13 +69,16 @@ export function notificationKeeperFactory(pushEmitter) {
65
69
  if (timestamp > c.cTime) {
66
70
  c.cTime = timestamp;
67
71
  if (controlType === ControlType.STREAMING_DISABLED) {
72
+ telemetryTracker.streamingEvent(STREAMING_STATUS, DISABLED);
68
73
  pushEmitter.emit(PUSH_NONRETRYABLE_ERROR);
69
74
  }
70
75
  else if (hasPublishers) {
71
76
  if (controlType === ControlType.STREAMING_PAUSED && hasResumed) {
77
+ telemetryTracker.streamingEvent(STREAMING_STATUS, PAUSED);
72
78
  pushEmitter.emit(PUSH_SUBSYSTEM_DOWN);
73
79
  }
74
80
  else if (controlType === ControlType.STREAMING_RESUMED && !hasResumed) {
81
+ telemetryTracker.streamingEvent(STREAMING_STATUS, ENABLED);
75
82
  pushEmitter.emit(PUSH_SUBSYSTEM_UP);
76
83
  }
77
84
  // nothing to do when hasPublishers === false:
@@ -2,27 +2,33 @@ import { errorParser, messageParser } from './NotificationParser';
2
2
  import { notificationKeeperFactory } from './NotificationKeeper';
3
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';
4
4
  import { STREAMING_PARSING_ERROR_FAILS, ERROR_STREAMING_SSE, STREAMING_PARSING_MESSAGE_FAILS, STREAMING_NEW_MESSAGE } from '../../../logger/constants';
5
- function isRetryableError(error) {
6
- if (error.parsedData && error.parsedData.code) {
7
- var code = error.parsedData.code;
8
- // 401 errors due to invalid or expired token (e.g., if refresh token coudn't be executed)
9
- if (40140 <= code && code <= 40149)
10
- return true;
11
- // Others 4XX errors (e.g., bad request from the SDK)
12
- if (40000 <= code && code <= 49999)
13
- return false;
14
- }
15
- // network errors or 5XX HTTP errors
16
- return true;
17
- }
5
+ import { ABLY_ERROR, NON_REQUESTED, SSE_CONNECTION_ERROR } from '../../../utils/constants';
18
6
  /**
19
7
  * Factory for SSEHandler, which processes SSEClient messages and emits the corresponding push events.
20
8
  *
21
9
  * @param log factory logger
22
10
  * @param pushEmitter emitter for events related to streaming support
23
11
  */
24
- export function SSEHandlerFactory(log, pushEmitter) {
25
- var notificationKeeper = notificationKeeperFactory(pushEmitter);
12
+ export function SSEHandlerFactory(log, pushEmitter, telemetryTracker) {
13
+ var notificationKeeper = notificationKeeperFactory(pushEmitter, telemetryTracker);
14
+ function isRetryableError(error) {
15
+ if (error.parsedData && error.parsedData.code) {
16
+ // Ably error
17
+ var code = error.parsedData.code;
18
+ telemetryTracker.streamingEvent(ABLY_ERROR, code);
19
+ // 401 errors due to invalid or expired token (e.g., if refresh token coudn't be executed)
20
+ if (40140 <= code && code <= 40149)
21
+ return true;
22
+ // Others 4XX errors (e.g., bad request from the SDK)
23
+ if (40000 <= code && code <= 49999)
24
+ return false;
25
+ }
26
+ else {
27
+ // network errors or 5XX HTTP errors
28
+ telemetryTracker.streamingEvent(SSE_CONNECTION_ERROR, NON_REQUESTED);
29
+ }
30
+ return true;
31
+ }
26
32
  return {
27
33
  handleOpen: function () {
28
34
  notificationKeeper.handleOpen();
@@ -14,13 +14,14 @@ import { UpdateStrategy } from './SSEHandler/types';
14
14
  import { isInBitmap, parseBitmap, parseKeyList } from './mySegmentsV2utils';
15
15
  import { _Set } from '../../utils/lang/sets';
16
16
  import { hash64 } from '../../utils/murmur3/murmur3_64';
17
+ import { TOKEN_REFRESH, AUTH_REJECTION } from '../../utils/constants';
17
18
  /**
18
19
  * PushManager factory:
19
20
  * - for server-side if key is not provided in settings.
20
21
  * - for client-side, with support for multiple clients, if key is provided in settings
21
22
  */
22
23
  export function pushManagerFactory(params, pollingManager) {
23
- var settings = params.settings, storage = params.storage, splitApi = params.splitApi, readiness = params.readiness, platform = params.platform;
24
+ var settings = params.settings, storage = params.storage, splitApi = params.splitApi, readiness = params.readiness, platform = params.platform, telemetryTracker = params.telemetryTracker;
24
25
  // `userKey` is the matching key of main client in client-side SDK.
25
26
  // It can be used to check if running on client-side or server-side SDK.
26
27
  var userKey = settings.core.key ? getMatching(settings.core.key) : undefined;
@@ -37,7 +38,7 @@ export function pushManagerFactory(params, pollingManager) {
37
38
  var authenticate = authenticateFactory(splitApi.fetchAuth);
38
39
  // init feedback loop
39
40
  var pushEmitter = new platform.EventEmitter();
40
- var sseHandler = SSEHandlerFactory(log, pushEmitter);
41
+ var sseHandler = SSEHandlerFactory(log, pushEmitter, telemetryTracker);
41
42
  sseClient.setEventHandler(sseHandler);
42
43
  // init workers
43
44
  // MySegmentsUpdateWorker (client-side) are initiated in `add` method
@@ -80,6 +81,7 @@ export function pushManagerFactory(params, pollingManager) {
80
81
  return;
81
82
  sseClient.open(authData);
82
83
  }, connDelay * 1000);
84
+ telemetryTracker.streamingEvent(TOKEN_REFRESH, decodedToken.exp);
83
85
  }
84
86
  function connectPush() {
85
87
  // Guard condition in case `stop/disconnectPush` has been called (e.g., calling SDK destroy, or app signal close/background)
@@ -110,6 +112,7 @@ export function pushManagerFactory(params, pollingManager) {
110
112
  log.error(ERROR_STREAMING_AUTH, [error.message]);
111
113
  // Handle 4XX HTTP errors: 401 (invalid API Key) or 400 (using incorrect API Key, i.e., client-side API Key on server-side)
112
114
  if (error.statusCode >= 400 && error.statusCode < 500) {
115
+ telemetryTracker.streamingEvent(AUTH_REJECTION);
113
116
  pushEmitter.emit(PUSH_NONRETRYABLE_ERROR);
114
117
  return;
115
118
  }
@@ -150,14 +153,14 @@ export function pushManagerFactory(params, pollingManager) {
150
153
  connectPushRetryBackoff.reset();
151
154
  stopWorkers();
152
155
  });
153
- /** Fallbacking without retry due to: STREAMING_DISABLED control event, or 'pushEnabled: false', or non-recoverable SSE and Authentication errors */
156
+ /** Fallback to polling without retry due to: STREAMING_DISABLED control event, or 'pushEnabled: false', or non-recoverable SSE and Authentication errors */
154
157
  pushEmitter.on(PUSH_NONRETRYABLE_ERROR, function handleNonRetryableError() {
155
158
  disabled = true;
156
159
  // Note: `stopWorkers` is been called twice, but it is not harmful
157
160
  disconnectPush();
158
161
  pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already
159
162
  });
160
- /** Fallbacking with retry due to recoverable SSE and Authentication errors */
163
+ /** Fallback to polling with retry due to recoverable SSE and Authentication errors */
161
164
  pushEmitter.on(PUSH_RETRYABLE_ERROR, function handleRetryableError() {
162
165
  // SSE connection is closed to avoid repeated errors due to retries
163
166
  sseClient.close();
@@ -0,0 +1,24 @@
1
+ import { submitterFactory, firstPushWindowDecorator } from './submitter';
2
+ import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
3
+ var DATA_NAME = 'events';
4
+ /**
5
+ * Submitter that periodically posts tracked events
6
+ */
7
+ export function eventsSubmitterFactory(params) {
8
+ var _a = params.settings, log = _a.log, eventsPushRate = _a.scheduler.eventsPushRate, eventsFirstPushWindow = _a.startup.eventsFirstPushWindow, postEventsBulk = params.splitApi.postEventsBulk, events = params.storage.events;
9
+ // don't retry events.
10
+ var submitter = submitterFactory(log, postEventsBulk, events, eventsPushRate, DATA_NAME);
11
+ // Set a timer for the first push window of events.
12
+ if (eventsFirstPushWindow > 0)
13
+ submitter = firstPushWindowDecorator(submitter, eventsFirstPushWindow);
14
+ // register events submitter to be executed when events cache is full
15
+ events.setOnFullQueueCb(function () {
16
+ if (submitter.isRunning()) {
17
+ log.info(SUBMITTERS_PUSH_FULL_QUEUE, [DATA_NAME]);
18
+ submitter.execute();
19
+ }
20
+ // If submitter is stopped (e.g., user consent declined or unknown, or app state offline), we don't send the data.
21
+ // Data will be sent when submitter is resumed.
22
+ });
23
+ return submitter;
24
+ }
@@ -1,4 +1,4 @@
1
- import { submitterSyncTaskFactory } from './submitterSyncTask';
1
+ import { submitterFactory } from './submitter';
2
2
  /**
3
3
  * Converts `impressionCounts` data from cache into request payload.
4
4
  */
@@ -22,9 +22,12 @@ export function fromImpressionCountsCollector(impressionsCount) {
22
22
  }
23
23
  var IMPRESSIONS_COUNT_RATE = 1800000; // 30 minutes
24
24
  /**
25
- * Sync task that periodically posts impression counts
25
+ * Submitter that periodically posts impression counts
26
26
  */
27
- export function impressionCountsSyncTaskFactory(log, postTestImpressionsCount, impressionCountsCache, latencyTracker) {
28
- // retry impressions counts only once.
29
- return submitterSyncTaskFactory(log, postTestImpressionsCount, impressionCountsCache, IMPRESSIONS_COUNT_RATE, 'impression counts', latencyTracker, fromImpressionCountsCollector, 1);
27
+ export function impressionCountsSubmitterFactory(params) {
28
+ var log = params.settings.log, postTestImpressionsCount = params.splitApi.postTestImpressionsCount, impressionCounts = params.storage.impressionCounts;
29
+ if (impressionCounts) {
30
+ // retry impressions counts only once.
31
+ return submitterFactory(log, postTestImpressionsCount, impressionCounts, IMPRESSIONS_COUNT_RATE, 'impression counts', fromImpressionCountsCollector, 1);
32
+ }
30
33
  }
@@ -1,5 +1,5 @@
1
1
  import { groupBy, forOwn } from '../../utils/lang';
2
- import { submitterSyncTaskFactory } from './submitterSyncTask';
2
+ import { submitterFactory } from './submitter';
3
3
  import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
4
4
  var DATA_NAME = 'impressions';
5
5
  /**
@@ -29,14 +29,14 @@ export function fromImpressionsCollector(sendLabels, data) {
29
29
  return dto;
30
30
  }
31
31
  /**
32
- * Sync task that periodically posts impressions data
32
+ * Submitter that periodically posts impressions data
33
33
  */
34
- export function impressionsSyncTaskFactory(log, postTestImpressionsBulk, impressionsCache, impressionsRefreshRate, sendLabels, latencyTracker) {
35
- if (sendLabels === void 0) { sendLabels = false; }
34
+ export function impressionsSubmitterFactory(params) {
35
+ var _a = params.settings, log = _a.log, impressionsRefreshRate = _a.scheduler.impressionsRefreshRate, labelsEnabled = _a.core.labelsEnabled, postTestImpressionsBulk = params.splitApi.postTestImpressionsBulk, impressions = params.storage.impressions;
36
36
  // retry impressions only once.
37
- var syncTask = submitterSyncTaskFactory(log, postTestImpressionsBulk, impressionsCache, impressionsRefreshRate, DATA_NAME, latencyTracker, fromImpressionsCollector.bind(undefined, sendLabels), 1);
37
+ var syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, DATA_NAME, fromImpressionsCollector.bind(undefined, labelsEnabled), 1);
38
38
  // register impressions submitter to be executed when impressions cache is full
39
- impressionsCache.setOnFullQueueCb(function () {
39
+ impressions.setOnFullQueueCb(function () {
40
40
  if (syncTask.isRunning()) {
41
41
  log.info(SUBMITTERS_PUSH_FULL_QUEUE, [DATA_NAME]);
42
42
  syncTask.execute();
@@ -0,0 +1,61 @@
1
+ import { syncTaskFactory } from '../syncTask';
2
+ import { SUBMITTERS_PUSH, SUBMITTERS_PUSH_FAILS, SUBMITTERS_PUSH_RETRY } from '../../logger/constants';
3
+ /**
4
+ * Base function to create submitters, such as ImpressionsSubmitter and EventsSubmitter
5
+ */
6
+ export function submitterFactory(log, postClient, sourceCache, postRate, dataName, fromCacheToPayload, maxRetries, debugLogs // true for telemetry submitters
7
+ ) {
8
+ if (maxRetries === void 0) { maxRetries = 0; }
9
+ var retries = 0;
10
+ function postData() {
11
+ if (sourceCache.isEmpty())
12
+ return Promise.resolve();
13
+ var data = sourceCache.state();
14
+ // @ts-ignore
15
+ var dataCountMessage = typeof data.length === 'number' ? data.length + " " + dataName : dataName;
16
+ log[debugLogs ? 'debug' : 'info'](SUBMITTERS_PUSH, [dataCountMessage]);
17
+ var jsonPayload = JSON.stringify(fromCacheToPayload ? fromCacheToPayload(data) : data);
18
+ if (!maxRetries)
19
+ sourceCache.clear();
20
+ return postClient(jsonPayload).then(function () {
21
+ retries = 0;
22
+ sourceCache.clear(); // we clear the queue if request successes.
23
+ }).catch(function (err) {
24
+ if (!maxRetries) {
25
+ log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_FAILS, [dataCountMessage, err]);
26
+ }
27
+ else if (retries === maxRetries) {
28
+ retries = 0;
29
+ sourceCache.clear(); // we clear the queue if request fails after retries.
30
+ log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_FAILS, [dataCountMessage, err]);
31
+ }
32
+ else {
33
+ retries++;
34
+ log[debugLogs ? 'debug' : 'warn'](SUBMITTERS_PUSH_RETRY, [dataCountMessage, err]);
35
+ }
36
+ });
37
+ }
38
+ return syncTaskFactory(log, postData, postRate, dataName + ' submitter');
39
+ }
40
+ /**
41
+ * Decorates a provided submitter with a first execution window
42
+ */
43
+ export function firstPushWindowDecorator(submitter, firstPushWindow) {
44
+ var running = false;
45
+ var stopEventPublisherTimeout;
46
+ var originalStart = submitter.start;
47
+ submitter.start = function () {
48
+ running = true;
49
+ stopEventPublisherTimeout = setTimeout(originalStart, firstPushWindow);
50
+ };
51
+ var originalStop = submitter.stop;
52
+ submitter.stop = function () {
53
+ running = false;
54
+ clearTimeout(stopEventPublisherTimeout);
55
+ originalStop();
56
+ };
57
+ submitter.isRunning = function () {
58
+ return running;
59
+ };
60
+ return submitter;
61
+ }