@splitsoftware/splitio-commons 1.5.1-rc.0 → 1.5.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.
Files changed (67) hide show
  1. package/CHANGES.txt +1 -2
  2. package/cjs/integrations/ga/GaToSplit.js +11 -12
  3. package/cjs/services/splitApi.js +4 -4
  4. package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +5 -5
  5. package/cjs/sync/polling/fetchers/splitChangesFetcher.js +2 -2
  6. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +34 -34
  7. package/cjs/sync/polling/updaters/splitChangesUpdater.js +4 -3
  8. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +46 -46
  9. package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +82 -64
  10. package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +74 -58
  11. package/cjs/sync/streaming/UpdateWorkers/constants.js +6 -0
  12. package/cjs/sync/streaming/pushManager.js +6 -7
  13. package/cjs/sync/syncTask.js +13 -16
  14. package/cjs/utils/Backoff.js +3 -2
  15. package/esm/integrations/ga/GaToSplit.js +11 -12
  16. package/esm/services/splitApi.js +4 -4
  17. package/esm/sync/polling/fetchers/segmentChangesFetcher.js +5 -5
  18. package/esm/sync/polling/fetchers/splitChangesFetcher.js +2 -2
  19. package/esm/sync/polling/updaters/segmentChangesUpdater.js +34 -34
  20. package/esm/sync/polling/updaters/splitChangesUpdater.js +4 -3
  21. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +46 -47
  22. package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +82 -65
  23. package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +74 -59
  24. package/esm/sync/streaming/UpdateWorkers/constants.js +3 -0
  25. package/esm/sync/streaming/pushManager.js +6 -7
  26. package/esm/sync/syncTask.js +13 -16
  27. package/esm/utils/Backoff.js +3 -2
  28. package/package.json +1 -1
  29. package/src/integrations/ga/GaToSplit.ts +8 -14
  30. package/src/integrations/ga/types.ts +2 -13
  31. package/src/services/splitApi.ts +4 -4
  32. package/src/services/types.ts +2 -2
  33. package/src/sync/polling/fetchers/segmentChangesFetcher.ts +5 -4
  34. package/src/sync/polling/fetchers/splitChangesFetcher.ts +2 -1
  35. package/src/sync/polling/fetchers/types.ts +2 -0
  36. package/src/sync/polling/pollingManagerCS.ts +5 -5
  37. package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +2 -2
  38. package/src/sync/polling/types.ts +14 -6
  39. package/src/sync/polling/updaters/mySegmentsUpdater.ts +4 -4
  40. package/src/sync/polling/updaters/segmentChangesUpdater.ts +34 -32
  41. package/src/sync/polling/updaters/splitChangesUpdater.ts +5 -4
  42. package/src/sync/streaming/SSEHandler/types.ts +0 -7
  43. package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +45 -54
  44. package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +78 -63
  45. package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +73 -61
  46. package/src/sync/streaming/UpdateWorkers/constants.ts +3 -0
  47. package/src/sync/streaming/UpdateWorkers/types.ts +2 -4
  48. package/src/sync/streaming/pushManager.ts +12 -12
  49. package/src/sync/streaming/types.ts +2 -2
  50. package/src/sync/syncTask.ts +16 -18
  51. package/src/utils/Backoff.ts +7 -2
  52. package/types/integrations/ga/types.d.ts +2 -13
  53. package/types/services/types.d.ts +2 -2
  54. package/types/sync/polling/fetchers/types.d.ts +2 -2
  55. package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +2 -2
  56. package/types/sync/polling/types.d.ts +11 -6
  57. package/types/sync/polling/updaters/segmentChangesUpdater.d.ts +1 -1
  58. package/types/sync/polling/updaters/splitChangesUpdater.d.ts +1 -1
  59. package/types/sync/streaming/SSEHandler/types.d.ts +0 -4
  60. package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +3 -24
  61. package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +3 -23
  62. package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +6 -33
  63. package/types/sync/streaming/UpdateWorkers/types.d.ts +1 -2
  64. package/types/sync/streaming/types.d.ts +2 -2
  65. package/types/sync/syncTask.d.ts +2 -3
  66. package/types/utils/Backoff.d.ts +2 -0
  67. package/src/integrations/ga/autoRequire.js +0 -33
package/CHANGES.txt CHANGED
@@ -1,5 +1,4 @@
1
- 1.6.0 (July 7, 2022)
2
- - Added `autoRequire` configuration option to the Google Analytics to Split integration (See https://help.split.io/hc/en-us/articles/360040838752#set-up-with-gtm-and-gtag.js).
1
+ 1.5.1 (July XX, 2022)
3
2
  - Updated browser listener to push remaining impressions and events on 'visibilitychange' and 'pagehide' DOM events, instead of 'unload', which is not reliable in mobile and modern Web browsers (See https://developer.chrome.com/blog/page-lifecycle-api/#legacy-lifecycle-apis-to-avoid).
4
3
 
5
4
  1.5.0 (June 29, 2022)
@@ -10,24 +10,23 @@ var logNameMapper = 'ga-to-split:mapper';
10
10
  /**
11
11
  * Provides a plugin to use with analytics.js, accounting for the possibility
12
12
  * that the global command queue has been renamed or not yet defined.
13
- * @param window Reference to global object.
14
- * @param pluginName The plugin name identifier.
15
- * @param pluginConstructor The plugin constructor function.
16
- * @param log Logger instance.
17
- * @param autoRequire If true, log error when auto-require script is not detected
13
+ * @param {string} pluginName The plugin name identifier.
14
+ * @param {Function} pluginConstructor The plugin constructor function.
18
15
  */
19
- function providePlugin(window, pluginName, pluginConstructor, log, autoRequire) {
16
+ function providePlugin(pluginName, pluginConstructor) {
20
17
  // get reference to global command queue. Init it if not defined yet.
18
+ // @ts-expect-error
21
19
  var gaAlias = window.GoogleAnalyticsObject || 'ga';
22
20
  window[gaAlias] = window[gaAlias] || function () {
23
- (window[gaAlias].q = window[gaAlias].q || []).push(arguments);
21
+ var args = [];
22
+ for (var _i = 0; _i < arguments.length; _i++) {
23
+ args[_i] = arguments[_i];
24
+ }
25
+ (window[gaAlias].q = window[gaAlias].q || []).push(args);
24
26
  };
25
27
  // provides the plugin for use with analytics.js.
28
+ // @ts-expect-error
26
29
  window[gaAlias]('provide', pluginName, pluginConstructor);
27
- if (autoRequire && (!window[gaAlias].q || window[gaAlias].q.push === [].push)) {
28
- // Expecting spy on ga.q push method but not found
29
- log.error(logPrefix + 'integration is configured to autorequire the splitTracker plugin, but the necessary script does not seem to have run.');
30
- }
31
30
  }
32
31
  // Default mapping: object used for building the default mapper from hits to Split events
33
32
  var defaultMapping = {
@@ -247,6 +246,6 @@ function GaToSplit(sdkOptions, params) {
247
246
  return SplitTracker;
248
247
  }());
249
248
  // Register the plugin, even if config is invalid, since, if not provided, it will block `ga` command queue.
250
- providePlugin(window, 'splitTracker', SplitTracker, log, sdkOptions.autoRequire);
249
+ providePlugin('splitTracker', SplitTracker);
251
250
  }
252
251
  exports.GaToSplit = GaToSplit;
@@ -37,12 +37,12 @@ function splitApiFactory(settings, platform, telemetryTracker) {
37
37
  }
38
38
  return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_1.TOKEN));
39
39
  },
40
- fetchSplitChanges: function (since, noCache) {
41
- var url = urls.sdk + "/splitChanges?since=" + since + (filterQueryString || '');
40
+ fetchSplitChanges: function (since, noCache, till) {
41
+ var url = urls.sdk + "/splitChanges?since=" + since + (till ? '&till=' + till : '') + (filterQueryString || '');
42
42
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SPLITS));
43
43
  },
44
- fetchSegmentChanges: function (since, segmentName, noCache) {
45
- var url = urls.sdk + "/segmentChanges/" + segmentName + "?since=" + since;
44
+ fetchSegmentChanges: function (since, segmentName, noCache, till) {
45
+ var url = urls.sdk + "/segmentChanges/" + segmentName + "?since=" + since + (till ? '&till=' + till : '');
46
46
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SEGMENT));
47
47
  },
48
48
  fetchMySegments: function (userMatchingKey, noCache) {
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.segmentChangesFetcherFactory = void 0;
4
4
  var tslib_1 = require("tslib");
5
- function greedyFetch(fetchSegmentChanges, since, segmentName, noCache) {
6
- return fetchSegmentChanges(since, segmentName, noCache)
5
+ function greedyFetch(fetchSegmentChanges, since, segmentName, noCache, targetTill) {
6
+ return fetchSegmentChanges(since, segmentName, noCache, targetTill)
7
7
  .then(function (resp) { return resp.json(); })
8
8
  .then(function (json) {
9
9
  var since = json.since, till = json.till;
@@ -11,7 +11,7 @@ function greedyFetch(fetchSegmentChanges, since, segmentName, noCache) {
11
11
  return [json];
12
12
  }
13
13
  else {
14
- return Promise.all([json, greedyFetch(fetchSegmentChanges, till, segmentName, noCache)]).then(function (flatMe) {
14
+ return Promise.all([json, greedyFetch(fetchSegmentChanges, till, segmentName, noCache, targetTill)]).then(function (flatMe) {
15
15
  return (0, tslib_1.__spreadArray)([flatMe[0]], flatMe[1], true);
16
16
  });
17
17
  }
@@ -22,10 +22,10 @@ function greedyFetch(fetchSegmentChanges, since, segmentName, noCache) {
22
22
  * SegmentChanges fetcher is a wrapper around `segmentChanges` API service that parses the response and handle errors and retries.
23
23
  */
24
24
  function segmentChangesFetcherFactory(fetchSegmentChanges) {
25
- return function segmentChangesFetcher(since, segmentName, noCache,
25
+ return function segmentChangesFetcher(since, segmentName, noCache, till,
26
26
  // Optional decorator for `fetchMySegments` promise, such as timeout or time tracker
27
27
  decorator) {
28
- var segmentsPromise = greedyFetch(fetchSegmentChanges, since, segmentName, noCache);
28
+ var segmentsPromise = greedyFetch(fetchSegmentChanges, since, segmentName, noCache, till);
29
29
  if (decorator)
30
30
  segmentsPromise = decorator(segmentsPromise);
31
31
  return segmentsPromise;
@@ -6,10 +6,10 @@ exports.splitChangesFetcherFactory = void 0;
6
6
  * SplitChanges fetcher is a wrapper around `splitChanges` API service that parses the response and handle errors.
7
7
  */
8
8
  function splitChangesFetcherFactory(fetchSplitChanges) {
9
- return function splitChangesFetcher(since, noCache,
9
+ return function splitChangesFetcher(since, noCache, till,
10
10
  // Optional decorator for `fetchSplitChanges` promise, such as timeout or time tracker
11
11
  decorator) {
12
- var splitsPromise = fetchSplitChanges(since, noCache);
12
+ var splitsPromise = fetchSplitChanges(since, noCache, till);
13
13
  if (decorator)
14
14
  splitsPromise = decorator(splitsPromise);
15
15
  return splitsPromise.then(function (resp) { return resp.json(); });
@@ -18,54 +18,54 @@ var thenable_1 = require("../../../utils/promise/thenable");
18
18
  */
19
19
  function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, readiness) {
20
20
  var readyOnAlreadyExistentState = true;
21
+ function updateSegment(segmentName, noCache, till, fetchOnlyNew) {
22
+ log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Processing segment " + segmentName);
23
+ var sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
24
+ return sincePromise.then(function (since) {
25
+ // if fetchOnlyNew flag, avoid processing already fetched segments
26
+ if (fetchOnlyNew && since !== -1)
27
+ return -1;
28
+ return segmentChangesFetcher(since, segmentName, noCache, till).then(function (changes) {
29
+ var changeNumber = -1;
30
+ var results = [];
31
+ changes.forEach(function (x) {
32
+ if (x.added.length > 0)
33
+ results.push(segments.addToSegment(segmentName, x.added));
34
+ if (x.removed.length > 0)
35
+ results.push(segments.removeFromSegment(segmentName, x.removed));
36
+ if (x.added.length > 0 || x.removed.length > 0) {
37
+ results.push(segments.setChangeNumber(segmentName, x.till));
38
+ changeNumber = x.till;
39
+ }
40
+ log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Processed " + segmentName + " with till = " + x.till + ". Added: " + x.added.length + ". Removed: " + x.removed.length);
41
+ });
42
+ // If at least one storage operation result is a promise, join all in a single promise.
43
+ if (results.some(function (result) { return (0, thenable_1.thenable)(result); }))
44
+ return Promise.all(results).then(function () { return changeNumber; });
45
+ return changeNumber;
46
+ });
47
+ });
48
+ }
21
49
  /**
22
50
  * 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.
23
51
  * Thus, a false result doesn't imply that SDK_SEGMENTS_ARRIVED was not emitted.
24
52
  * Returned promise will not be rejected.
25
53
  *
26
- * @param {string[] | undefined} segmentNames list of segment names to fetch. By passing `undefined` it fetches the list of segments registered at the storage
27
- * @param {boolean | undefined} noCache true to revalidate data to fetch on a SEGMENT_UPDATE notifications.
28
54
  * @param {boolean | undefined} fetchOnlyNew if true, only fetch the segments that not exists, i.e., which `changeNumber` is equal to -1.
29
55
  * This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE notifications.
56
+ * @param {string | undefined} segmentName segment name to fetch. By passing `undefined` it fetches the list of segments registered at the storage
57
+ * @param {boolean | undefined} noCache true to revalidate data to fetch on a SEGMENT_UPDATE notifications.
58
+ * @param {number | undefined} till till target for the provided segmentName, for CDN bypass.
30
59
  */
31
- return function segmentChangesUpdater(segmentNames, noCache, fetchOnlyNew) {
60
+ return function segmentChangesUpdater(fetchOnlyNew, segmentName, noCache, till) {
32
61
  log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Started segments update");
33
62
  // If not a segment name provided, read list of available segments names to be updated.
34
- var segmentsPromise = Promise.resolve(segmentNames ? segmentNames : segments.getRegisteredSegments());
63
+ var segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
35
64
  return segmentsPromise.then(function (segmentNames) {
36
65
  // Async fetchers are collected here.
37
66
  var updaters = [];
38
- var _loop_1 = function (index) {
39
- var segmentName = segmentNames[index];
40
- log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Processing segment " + segmentName);
41
- var sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
42
- updaters.push(sincePromise.then(function (since) {
43
- // if fetchOnlyNew flag, avoid processing already fetched segments
44
- if (fetchOnlyNew && since !== -1)
45
- return -1;
46
- return segmentChangesFetcher(since, segmentName, noCache).then(function (changes) {
47
- var changeNumber = -1;
48
- var results = [];
49
- changes.forEach(function (x) {
50
- if (x.added.length > 0)
51
- results.push(segments.addToSegment(segmentName, x.added));
52
- if (x.removed.length > 0)
53
- results.push(segments.removeFromSegment(segmentName, x.removed));
54
- if (x.added.length > 0 || x.removed.length > 0) {
55
- results.push(segments.setChangeNumber(segmentName, x.till));
56
- changeNumber = x.till;
57
- }
58
- log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Processed " + segmentName + " with till = " + x.till + ". Added: " + x.added.length + ". Removed: " + x.removed.length);
59
- });
60
- // If at least one storage operation result is a promise, join all in a single promise.
61
- if (results.some(function (result) { return (0, thenable_1.thenable)(result); }))
62
- return Promise.all(results).then(function () { return changeNumber; });
63
- return changeNumber;
64
- });
65
- }));
66
- };
67
67
  for (var index = 0; index < segmentNames.length; index++) {
68
- _loop_1(index);
68
+ updaters.push(updateSegment(segmentNames[index], noCache, till, fetchOnlyNew));
69
69
  }
70
70
  return Promise.all(updaters).then(function (shouldUpdateFlags) {
71
71
  // if at least one segment fetch succeeded, mark segments ready
@@ -84,16 +84,17 @@ function splitChangesUpdaterFactory(log, splitChangesFetcher, splits, segments,
84
84
  * Returned promise will not be rejected.
85
85
  *
86
86
  * @param {boolean | undefined} noCache true to revalidate data to fetch
87
+ * @param {boolean | undefined} till query param to bypass CDN requests
87
88
  */
88
- return function splitChangesUpdater(noCache) {
89
+ return function splitChangesUpdater(noCache, till) {
89
90
  /**
90
91
  * @param {number} since current changeNumber at splitsCache
91
- * @param {number} retry current number of retry attemps
92
+ * @param {number} retry current number of retry attempts
92
93
  */
93
94
  function _splitChangesUpdater(since, retry) {
94
95
  if (retry === void 0) { retry = 0; }
95
96
  log.debug(constants_2.SYNC_SPLITS_FETCH, [since]);
96
- var fetcherPromise = splitChangesFetcher(since, noCache, _promiseDecorator)
97
+ var fetcherPromise = splitChangesFetcher(since, noCache, till, _promiseDecorator)
97
98
  .then(function (splitChanges) {
98
99
  startingUp = false;
99
100
  var mutation = computeSplitsMutation(splitChanges.splits);
@@ -3,59 +3,59 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MySegmentsUpdateWorker = void 0;
4
4
  var Backoff_1 = require("../../../utils/Backoff");
5
5
  /**
6
- * MySegmentsUpdateWorker class
6
+ * MySegmentsUpdateWorker factory
7
7
  */
8
- var MySegmentsUpdateWorker = /** @class */ (function () {
9
- /**
10
- * @param {Object} mySegmentsSyncTask task for syncing mySegments data
11
- */
12
- function MySegmentsUpdateWorker(mySegmentsSyncTask) {
13
- this.mySegmentsSyncTask = mySegmentsSyncTask;
14
- this.maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
15
- this.handleNewEvent = false;
16
- this.segmentsData = undefined; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber
17
- this.currentChangeNumber = -1; // @TODO: remove once `/mySegments` endpoint provides the changeNumber
18
- this.put = this.put.bind(this);
19
- this.__handleMySegmentsUpdateCall = this.__handleMySegmentsUpdateCall.bind(this);
20
- this.backoff = new Backoff_1.Backoff(this.__handleMySegmentsUpdateCall);
21
- }
22
- // Private method
23
- // Precondition: this.mySegmentsSyncTask.isSynchronizingMySegments === false
24
- MySegmentsUpdateWorker.prototype.__handleMySegmentsUpdateCall = function () {
25
- var _this = this;
26
- if (this.maxChangeNumber > this.currentChangeNumber) {
27
- this.handleNewEvent = false;
28
- var currentMaxChangeNumber_1 = this.maxChangeNumber;
8
+ function MySegmentsUpdateWorker(mySegmentsSyncTask) {
9
+ var maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
10
+ var currentChangeNumber = -1;
11
+ var handleNewEvent = false;
12
+ var isHandlingEvent;
13
+ var _segmentsData; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber
14
+ var backoff = new Backoff_1.Backoff(__handleMySegmentsUpdateCall);
15
+ function __handleMySegmentsUpdateCall() {
16
+ isHandlingEvent = true;
17
+ if (maxChangeNumber > currentChangeNumber) {
18
+ handleNewEvent = false;
19
+ var currentMaxChangeNumber_1 = maxChangeNumber;
29
20
  // fetch mySegments revalidating data if cached
30
- this.mySegmentsSyncTask.execute(this.segmentsData, true).then(function (result) {
21
+ mySegmentsSyncTask.execute(_segmentsData, true).then(function (result) {
22
+ if (!isHandlingEvent)
23
+ return; // halt if `stop` has been called
31
24
  if (result !== false) // Unlike `Splits|SegmentsUpdateWorker`, we cannot use `mySegmentsCache.getChangeNumber` since `/mySegments` endpoint doesn't provide this value.
32
- _this.currentChangeNumber = Math.max(_this.currentChangeNumber, currentMaxChangeNumber_1); // use `currentMaxChangeNumber`, in case that `this.maxChangeNumber` was updated during fetch.
33
- if (_this.handleNewEvent) {
34
- _this.__handleMySegmentsUpdateCall();
25
+ currentChangeNumber = Math.max(currentChangeNumber, currentMaxChangeNumber_1); // use `currentMaxChangeNumber`, in case that `maxChangeNumber` was updated during fetch.
26
+ if (handleNewEvent) {
27
+ __handleMySegmentsUpdateCall();
35
28
  }
36
29
  else {
37
- _this.backoff.scheduleCall();
30
+ backoff.scheduleCall();
38
31
  }
39
32
  });
40
33
  }
34
+ else {
35
+ isHandlingEvent = false;
36
+ }
37
+ }
38
+ return {
39
+ /**
40
+ * Invoked by NotificationProcessor on MY_SEGMENTS_UPDATE event
41
+ *
42
+ * @param {number} changeNumber change number of the MY_SEGMENTS_UPDATE notification
43
+ * @param {SegmentsData | undefined} segmentsData might be undefined
44
+ */
45
+ put: function (changeNumber, segmentsData) {
46
+ if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber)
47
+ return;
48
+ maxChangeNumber = changeNumber;
49
+ handleNewEvent = true;
50
+ _segmentsData = segmentsData;
51
+ if (backoff.timeoutID || !isHandlingEvent)
52
+ __handleMySegmentsUpdateCall();
53
+ backoff.reset();
54
+ },
55
+ stop: function () {
56
+ isHandlingEvent = false;
57
+ backoff.reset();
58
+ }
41
59
  };
42
- /**
43
- * Invoked by NotificationProcessor on MY_SEGMENTS_UPDATE event
44
- *
45
- * @param {number} changeNumber change number of the MY_SEGMENTS_UPDATE notification
46
- * @param {SegmentsData | undefined} segmentsData might be undefined
47
- */
48
- MySegmentsUpdateWorker.prototype.put = function (changeNumber, segmentsData) {
49
- if (changeNumber <= this.currentChangeNumber || changeNumber <= this.maxChangeNumber)
50
- return;
51
- this.maxChangeNumber = changeNumber;
52
- this.handleNewEvent = true;
53
- this.backoff.reset();
54
- this.segmentsData = segmentsData;
55
- if (this.mySegmentsSyncTask.isExecuting())
56
- return;
57
- this.__handleMySegmentsUpdateCall();
58
- };
59
- return MySegmentsUpdateWorker;
60
- }());
60
+ }
61
61
  exports.MySegmentsUpdateWorker = MySegmentsUpdateWorker;
@@ -2,73 +2,91 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SegmentsUpdateWorker = void 0;
4
4
  var Backoff_1 = require("../../../utils/Backoff");
5
+ var constants_1 = require("./constants");
5
6
  /**
6
- * SegmentUpdateWorker class
7
+ * SegmentsUpdateWorker factory
7
8
  */
8
- var SegmentsUpdateWorker = /** @class */ (function () {
9
- /**
10
- * @param {Object} segmentsCache segments data cache
11
- * @param {Object} segmentsSyncTask task for syncing segments data
12
- */
13
- function SegmentsUpdateWorker(segmentsSyncTask, segmentsCache) {
14
- this.segmentsCache = segmentsCache;
15
- this.segmentsSyncTask = segmentsSyncTask;
16
- this.maxChangeNumbers = {};
17
- this.handleNewEvent = false;
18
- this.put = this.put.bind(this);
19
- this.__handleSegmentUpdateCall = this.__handleSegmentUpdateCall.bind(this);
20
- this.backoff = new Backoff_1.Backoff(this.__handleSegmentUpdateCall);
9
+ function SegmentsUpdateWorker(log, segmentsSyncTask, segmentsCache) {
10
+ // Handles retries with CDN bypass per segment name
11
+ function SegmentUpdateWorker(segment) {
12
+ var maxChangeNumber = 0;
13
+ var handleNewEvent = false;
14
+ var isHandlingEvent;
15
+ var cdnBypass;
16
+ var backoff = new Backoff_1.Backoff(__handleSegmentUpdateCall, constants_1.FETCH_BACKOFF_BASE, constants_1.FETCH_BACKOFF_MAX_WAIT);
17
+ function __handleSegmentUpdateCall() {
18
+ isHandlingEvent = true;
19
+ if (maxChangeNumber > segmentsCache.getChangeNumber(segment)) {
20
+ handleNewEvent = false;
21
+ // fetch segments revalidating data if cached
22
+ segmentsSyncTask.execute(false, segment, true, cdnBypass ? maxChangeNumber : undefined).then(function () {
23
+ if (!isHandlingEvent)
24
+ return; // halt if `stop` has been called
25
+ if (handleNewEvent) {
26
+ __handleSegmentUpdateCall();
27
+ }
28
+ else {
29
+ var attempts = backoff.attempts + 1;
30
+ if (maxChangeNumber <= segmentsCache.getChangeNumber(segment)) {
31
+ log.debug("Refresh completed" + (cdnBypass ? ' bypassing the CDN' : '') + " in " + attempts + " attempts.");
32
+ isHandlingEvent = false;
33
+ return;
34
+ }
35
+ if (attempts < constants_1.FETCH_BACKOFF_MAX_RETRIES) {
36
+ backoff.scheduleCall();
37
+ return;
38
+ }
39
+ if (cdnBypass) {
40
+ log.debug("No changes fetched after " + attempts + " attempts with CDN bypassed.");
41
+ isHandlingEvent = false;
42
+ }
43
+ else {
44
+ backoff.reset();
45
+ cdnBypass = true;
46
+ __handleSegmentUpdateCall();
47
+ }
48
+ }
49
+ });
50
+ }
51
+ else {
52
+ isHandlingEvent = false;
53
+ }
54
+ }
55
+ return {
56
+ put: function (changeNumber) {
57
+ var currentChangeNumber = segmentsCache.getChangeNumber(segment);
58
+ if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber)
59
+ return;
60
+ maxChangeNumber = changeNumber;
61
+ handleNewEvent = true;
62
+ cdnBypass = false;
63
+ if (backoff.timeoutID || !isHandlingEvent)
64
+ __handleSegmentUpdateCall();
65
+ backoff.reset();
66
+ },
67
+ stop: function () {
68
+ isHandlingEvent = false;
69
+ backoff.reset();
70
+ }
71
+ };
21
72
  }
22
- // Private method
23
- // Precondition: this.segmentsSyncTask.isSynchronizingSegments === false
24
- // Approach similar to MySegmentsUpdateWorker due to differences on Segments notifications and endpoint changeNumbers
25
- SegmentsUpdateWorker.prototype.__handleSegmentUpdateCall = function () {
26
- var _this = this;
27
- var segmentsToFetch = Object.keys(this.maxChangeNumbers).filter(function (segmentName) {
28
- return _this.maxChangeNumbers[segmentName] > _this.segmentsCache.getChangeNumber(segmentName);
29
- });
30
- if (segmentsToFetch.length > 0) {
31
- this.handleNewEvent = false;
32
- var currentMaxChangeNumbers_1 = segmentsToFetch.map(function (segmentToFetch) { return _this.maxChangeNumbers[segmentToFetch]; });
33
- // fetch segments revalidating data if cached
34
- this.segmentsSyncTask.execute(segmentsToFetch, true).then(function (result) {
35
- // Unlike `SplitUpdateWorker` where changeNumber is consistent between notification and endpoint, if there is no error,
36
- // we must clean the `maxChangeNumbers` of those segments that didn't receive a new update notification during the fetch.
37
- if (result !== false) {
38
- segmentsToFetch.forEach(function (fetchedSegment, index) {
39
- if (_this.maxChangeNumbers[fetchedSegment] === currentMaxChangeNumbers_1[index])
40
- _this.maxChangeNumbers[fetchedSegment] = -1;
41
- });
42
- }
43
- else {
44
- // recursive invocation with backoff if there was some error
45
- _this.backoff.scheduleCall();
46
- }
47
- // immediate recursive invocation if a new notification was queued during fetch
48
- if (_this.handleNewEvent) {
49
- _this.__handleSegmentUpdateCall();
50
- }
51
- });
73
+ var segments = {};
74
+ return {
75
+ /**
76
+ * Invoked by NotificationProcessor on SEGMENT_UPDATE event
77
+ *
78
+ * @param {number} changeNumber change number of the SEGMENT_UPDATE notification
79
+ * @param {string} segmentName segment name of the SEGMENT_UPDATE notification
80
+ */
81
+ put: function (_a) {
82
+ var changeNumber = _a.changeNumber, segmentName = _a.segmentName;
83
+ if (!segments[segmentName])
84
+ segments[segmentName] = SegmentUpdateWorker(segmentName);
85
+ segments[segmentName].put(changeNumber);
86
+ },
87
+ stop: function () {
88
+ Object.keys(segments).forEach(function (segmentName) { return segments[segmentName].stop(); });
52
89
  }
53
90
  };
54
- /**
55
- * Invoked by NotificationProcessor on SEGMENT_UPDATE event
56
- *
57
- * @param {number} changeNumber change number of the SEGMENT_UPDATE notification
58
- * @param {string} segmentName segment name of the SEGMENT_UPDATE notification
59
- */
60
- SegmentsUpdateWorker.prototype.put = function (_a) {
61
- var changeNumber = _a.changeNumber, segmentName = _a.segmentName;
62
- var currentChangeNumber = this.segmentsCache.getChangeNumber(segmentName);
63
- if (changeNumber <= currentChangeNumber || changeNumber <= this.maxChangeNumbers[segmentName])
64
- return;
65
- this.maxChangeNumbers[segmentName] = changeNumber;
66
- this.handleNewEvent = true;
67
- this.backoff.reset();
68
- if (this.segmentsSyncTask.isExecuting())
69
- return;
70
- this.__handleSegmentUpdateCall();
71
- };
72
- return SegmentsUpdateWorker;
73
- }());
91
+ }
74
92
  exports.SegmentsUpdateWorker = SegmentsUpdateWorker;