@splitsoftware/splitio-commons 1.15.1-rc.3 → 1.16.1-rc.0

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 (141) hide show
  1. package/CHANGES.txt +5 -3
  2. package/cjs/evaluator/matchers/index.js +3 -1
  3. package/cjs/evaluator/matchers/large_segment.js +16 -0
  4. package/cjs/evaluator/matchers/matcherTypes.js +1 -0
  5. package/cjs/evaluator/matchersTransform/index.js +1 -1
  6. package/cjs/logger/constants.js +4 -4
  7. package/cjs/logger/messages/info.js +0 -1
  8. package/cjs/readiness/readinessManager.js +11 -6
  9. package/cjs/readiness/sdkReadinessManager.js +5 -6
  10. package/cjs/sdkClient/sdkClientMethodCS.js +3 -4
  11. package/cjs/sdkClient/sdkClientMethodCSWithTT.js +4 -5
  12. package/cjs/sdkFactory/index.js +1 -1
  13. package/cjs/services/splitApi.js +4 -0
  14. package/cjs/storages/AbstractSplitsCacheAsync.js +2 -2
  15. package/cjs/storages/AbstractSplitsCacheSync.js +5 -5
  16. package/cjs/storages/KeyBuilder.js +3 -0
  17. package/cjs/storages/KeyBuilderCS.js +17 -5
  18. package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +16 -4
  19. package/cjs/storages/inLocalStorage/index.js +6 -2
  20. package/cjs/storages/inMemory/InMemoryStorageCS.js +5 -0
  21. package/cjs/storages/inMemory/SplitsCacheInMemory.js +20 -11
  22. package/cjs/storages/inMemory/TelemetryCacheInMemory.js +7 -10
  23. package/cjs/sync/polling/pollingManagerCS.js +54 -30
  24. package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  25. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +13 -8
  26. package/cjs/sync/polling/updaters/splitChangesUpdater.js +2 -1
  27. package/cjs/sync/streaming/SSEHandler/index.js +1 -0
  28. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +6 -5
  29. package/cjs/sync/streaming/constants.js +2 -1
  30. package/cjs/sync/streaming/pushManager.js +96 -64
  31. package/cjs/sync/submitters/telemetrySubmitter.js +2 -0
  32. package/cjs/sync/syncManagerOnline.js +24 -14
  33. package/cjs/utils/constants/index.js +5 -1
  34. package/cjs/utils/settingsValidation/index.js +9 -4
  35. package/esm/evaluator/matchers/index.js +3 -1
  36. package/esm/evaluator/matchers/large_segment.js +12 -0
  37. package/esm/evaluator/matchers/matcherTypes.js +1 -0
  38. package/esm/evaluator/matchersTransform/index.js +1 -1
  39. package/esm/logger/constants.js +1 -1
  40. package/esm/logger/messages/info.js +0 -1
  41. package/esm/readiness/readinessManager.js +11 -6
  42. package/esm/readiness/sdkReadinessManager.js +5 -6
  43. package/esm/sdkClient/sdkClientMethodCS.js +4 -5
  44. package/esm/sdkClient/sdkClientMethodCSWithTT.js +5 -6
  45. package/esm/sdkFactory/index.js +1 -1
  46. package/esm/services/splitApi.js +5 -1
  47. package/esm/storages/AbstractSplitsCacheAsync.js +2 -2
  48. package/esm/storages/AbstractSplitsCacheSync.js +3 -3
  49. package/esm/storages/KeyBuilder.js +3 -0
  50. package/esm/storages/KeyBuilderCS.js +15 -4
  51. package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +17 -5
  52. package/esm/storages/inLocalStorage/index.js +7 -3
  53. package/esm/storages/inMemory/InMemoryStorageCS.js +5 -0
  54. package/esm/storages/inMemory/SplitsCacheInMemory.js +21 -12
  55. package/esm/storages/inMemory/TelemetryCacheInMemory.js +7 -10
  56. package/esm/sync/polling/pollingManagerCS.js +55 -31
  57. package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
  58. package/esm/sync/polling/updaters/mySegmentsUpdater.js +11 -6
  59. package/esm/sync/polling/updaters/splitChangesUpdater.js +2 -1
  60. package/esm/sync/streaming/SSEHandler/index.js +2 -1
  61. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +6 -5
  62. package/esm/sync/streaming/constants.js +1 -0
  63. package/esm/sync/streaming/pushManager.js +96 -65
  64. package/esm/sync/submitters/telemetrySubmitter.js +2 -0
  65. package/esm/sync/syncManagerOnline.js +25 -15
  66. package/esm/utils/constants/index.js +4 -0
  67. package/esm/utils/settingsValidation/index.js +10 -5
  68. package/package.json +1 -1
  69. package/src/dtos/types.ts +7 -1
  70. package/src/evaluator/matchers/index.ts +2 -0
  71. package/src/evaluator/matchers/large_segment.ts +18 -0
  72. package/src/evaluator/matchers/matcherTypes.ts +1 -0
  73. package/src/evaluator/matchersTransform/index.ts +1 -1
  74. package/src/logger/constants.ts +1 -1
  75. package/src/logger/messages/info.ts +0 -1
  76. package/src/readiness/readinessManager.ts +11 -5
  77. package/src/readiness/sdkReadinessManager.ts +7 -7
  78. package/src/readiness/types.ts +3 -2
  79. package/src/sdkClient/sdkClientMethodCS.ts +4 -6
  80. package/src/sdkClient/sdkClientMethodCSWithTT.ts +5 -7
  81. package/src/sdkFactory/index.ts +1 -1
  82. package/src/services/splitApi.ts +6 -1
  83. package/src/services/types.ts +1 -0
  84. package/src/storages/AbstractSplitsCacheAsync.ts +2 -2
  85. package/src/storages/AbstractSplitsCacheSync.ts +4 -4
  86. package/src/storages/KeyBuilder.ts +3 -0
  87. package/src/storages/KeyBuilderCS.ts +25 -5
  88. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +3 -3
  89. package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +20 -5
  90. package/src/storages/inLocalStorage/index.ts +8 -4
  91. package/src/storages/inMemory/InMemoryStorageCS.ts +5 -0
  92. package/src/storages/inMemory/SplitsCacheInMemory.ts +15 -10
  93. package/src/storages/inMemory/TelemetryCacheInMemory.ts +7 -11
  94. package/src/storages/types.ts +6 -4
  95. package/src/sync/polling/pollingManagerCS.ts +62 -27
  96. package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +8 -9
  97. package/src/sync/polling/types.ts +4 -3
  98. package/src/sync/polling/updaters/mySegmentsUpdater.ts +13 -10
  99. package/src/sync/polling/updaters/splitChangesUpdater.ts +4 -3
  100. package/src/sync/streaming/SSEHandler/index.ts +2 -1
  101. package/src/sync/streaming/SSEHandler/types.ts +14 -2
  102. package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +7 -5
  103. package/src/sync/streaming/constants.ts +1 -0
  104. package/src/sync/streaming/pushManager.ts +101 -63
  105. package/src/sync/streaming/types.ts +5 -3
  106. package/src/sync/submitters/telemetrySubmitter.ts +2 -0
  107. package/src/sync/submitters/types.ts +10 -4
  108. package/src/sync/syncManagerOnline.ts +19 -11
  109. package/src/types.ts +26 -1
  110. package/src/utils/constants/index.ts +5 -0
  111. package/src/utils/settingsValidation/index.ts +11 -6
  112. package/src/utils/settingsValidation/types.ts +1 -1
  113. package/types/dtos/types.d.ts +5 -1
  114. package/types/evaluator/matchers/large_segment.d.ts +5 -0
  115. package/types/logger/constants.d.ts +1 -1
  116. package/types/readiness/readinessManager.d.ts +2 -2
  117. package/types/readiness/sdkReadinessManager.d.ts +2 -3
  118. package/types/readiness/types.d.ts +3 -2
  119. package/types/services/types.d.ts +1 -0
  120. package/types/storages/AbstractSplitsCacheAsync.d.ts +1 -1
  121. package/types/storages/AbstractSplitsCacheSync.d.ts +3 -3
  122. package/types/storages/KeyBuilder.d.ts +1 -0
  123. package/types/storages/KeyBuilderCS.d.ts +7 -2
  124. package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +2 -2
  125. package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +1 -1
  126. package/types/storages/inMemory/SplitsCacheInMemory.d.ts +3 -2
  127. package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +4 -6
  128. package/types/storages/types.d.ts +4 -3
  129. package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +2 -3
  130. package/types/sync/polling/types.d.ts +10 -3
  131. package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +4 -4
  132. package/types/sync/streaming/SSEHandler/types.d.ts +13 -2
  133. package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -1
  134. package/types/sync/streaming/constants.d.ts +1 -0
  135. package/types/sync/streaming/pushManager.d.ts +2 -0
  136. package/types/sync/streaming/types.d.ts +5 -4
  137. package/types/sync/submitters/types.d.ts +9 -3
  138. package/types/types.d.ts +25 -0
  139. package/types/utils/constants/index.d.ts +3 -0
  140. package/types/utils/settingsValidation/index.d.ts +2 -0
  141. package/types/utils/settingsValidation/types.d.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  import { ISplit } from '../../dtos/types';
2
- import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
2
+ import { AbstractSplitsCacheSync, usesMatcher } from '../AbstractSplitsCacheSync';
3
3
  import { isFiniteNumber, toNumber, isNaNNumber } from '../../utils/lang';
4
4
  import { KeyBuilderCS } from '../KeyBuilderCS';
5
5
  import { ILogger } from '../../logger/types';
@@ -7,6 +7,7 @@ import { LOG_PREFIX } from './constants';
7
7
  import { ISet, _Set, setToArray } from '../../utils/lang/sets';
8
8
  import { ISettings } from '../../types';
9
9
  import { getStorageHash } from '../KeyBuilder';
10
+ import { IN_LARGE_SEGMENT, IN_SEGMENT } from '../../utils/constants';
10
11
 
11
12
  /**
12
13
  * ISplitsCacheSync implementation that stores split definitions in browser LocalStorage.
@@ -50,10 +51,15 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
50
51
  const ttKey = this.keys.buildTrafficTypeKey(split.trafficTypeName);
51
52
  this._decrementCount(ttKey);
52
53
 
53
- if (usesSegments(split)) {
54
+ if (usesMatcher(split, IN_SEGMENT)) {
54
55
  const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
55
56
  this._decrementCount(segmentsCountKey);
56
57
  }
58
+
59
+ if (usesMatcher(split, IN_LARGE_SEGMENT)) {
60
+ const segmentsCountKey = this.keys.buildSplitsWithLargeSegmentCountKey();
61
+ this._decrementCount(segmentsCountKey);
62
+ }
57
63
  }
58
64
  } catch (e) {
59
65
  this.log.error(LOG_PREFIX + e);
@@ -67,11 +73,17 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
67
73
  // @ts-expect-error
68
74
  localStorage.setItem(ttKey, toNumber(localStorage.getItem(ttKey)) + 1);
69
75
 
70
- if (usesSegments(split)) {
76
+ if (usesMatcher(split, IN_SEGMENT)) {
71
77
  const segmentsCountKey = this.keys.buildSplitsWithSegmentCountKey();
72
78
  // @ts-expect-error
73
79
  localStorage.setItem(segmentsCountKey, toNumber(localStorage.getItem(segmentsCountKey)) + 1);
74
80
  }
81
+
82
+ if (usesMatcher(split, IN_LARGE_SEGMENT)) {
83
+ const segmentsCountKey = this.keys.buildSplitsWithLargeSegmentCountKey();
84
+ // @ts-expect-error
85
+ localStorage.setItem(segmentsCountKey, toNumber(localStorage.getItem(segmentsCountKey)) + 1);
86
+ }
75
87
  }
76
88
  } catch (e) {
77
89
  this.log.error(LOG_PREFIX + e);
@@ -203,11 +215,14 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
203
215
  return isFiniteNumber(ttCount) && ttCount > 0;
204
216
  }
205
217
 
206
- usesSegments() {
218
+ usesMatcher(matcherType: string) {
207
219
  // If cache hasn't been synchronized with the cloud, assume we need them.
208
220
  if (!this.hasSync) return true;
209
221
 
210
- const storedCount = localStorage.getItem(this.keys.buildSplitsWithSegmentCountKey());
222
+ const storedCount = localStorage.getItem(matcherType === IN_SEGMENT ?
223
+ this.keys.buildSplitsWithSegmentCountKey() :
224
+ this.keys.buildSplitsWithLargeSegmentCountKey()
225
+ );
211
226
  const splitsWithSegmentsCount = storedCount === null ? 0 : toNumber(storedCount);
212
227
 
213
228
  if (isFiniteNumber(splitsWithSegmentsCount)) {
@@ -3,7 +3,7 @@ import { ImpressionCountsCacheInMemory } from '../inMemory/ImpressionCountsCache
3
3
  import { EventsCacheInMemory } from '../inMemory/EventsCacheInMemory';
4
4
  import { IStorageFactoryParams, IStorageSync, IStorageSyncFactory } from '../types';
5
5
  import { validatePrefix } from '../KeyBuilder';
6
- import { KeyBuilderCS } from '../KeyBuilderCS';
6
+ import { KeyBuilderCS, myLargeSegmentsKeyBuilder } from '../KeyBuilderCS';
7
7
  import { isLocalStorageAvailable } from '../../utils/env/isLocalStorageAvailable';
8
8
  import { SplitsCacheInLocal } from './SplitsCacheInLocal';
9
9
  import { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
@@ -38,15 +38,17 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
38
38
 
39
39
  const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation } } } = params;
40
40
  const matchingKey = getMatching(settings.core.key);
41
- const keys = new KeyBuilderCS(prefix, matchingKey as string);
41
+ const keys = new KeyBuilderCS(prefix, matchingKey);
42
42
  const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
43
43
 
44
44
  const splits = new SplitsCacheInLocal(settings, keys, expirationTimestamp);
45
45
  const segments = new MySegmentsCacheInLocal(log, keys);
46
+ const largeSegments = new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey));
46
47
 
47
48
  return {
48
49
  splits,
49
50
  segments,
51
+ largeSegments,
50
52
  impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
51
53
  impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
52
54
  events: new EventsCacheInMemory(eventsQueueSize),
@@ -56,6 +58,7 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
56
58
  destroy() {
57
59
  this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
58
60
  this.segments = new MySegmentsCacheInMemory();
61
+ this.largeSegments = new MySegmentsCacheInMemory();
59
62
  this.impressions.clear();
60
63
  this.impressionCounts && this.impressionCounts.clear();
61
64
  this.events.clear();
@@ -64,11 +67,11 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
64
67
 
65
68
  // When using shared instanciation with MEMORY we reuse everything but segments (they are customer per key).
66
69
  shared(matchingKey: string) {
67
- const childKeysBuilder = new KeyBuilderCS(prefix, matchingKey);
68
70
 
69
71
  return {
70
72
  splits: this.splits,
71
- segments: new MySegmentsCacheInLocal(log, childKeysBuilder),
73
+ segments: new MySegmentsCacheInLocal(log, new KeyBuilderCS(prefix, matchingKey)),
74
+ largeSegments: new MySegmentsCacheInLocal(log, myLargeSegmentsKeyBuilder(prefix, matchingKey)),
72
75
  impressions: this.impressions,
73
76
  impressionCounts: this.impressionCounts,
74
77
  events: this.events,
@@ -77,6 +80,7 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
77
80
  destroy() {
78
81
  this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
79
82
  this.segments = new MySegmentsCacheInMemory();
83
+ this.largeSegments = new MySegmentsCacheInMemory();
80
84
  }
81
85
  };
82
86
  },
@@ -18,10 +18,12 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
18
18
 
19
19
  const splits = new SplitsCacheInMemory(__splitFiltersValidation);
20
20
  const segments = new MySegmentsCacheInMemory();
21
+ const largeSegments = new MySegmentsCacheInMemory();
21
22
 
22
23
  const storage = {
23
24
  splits,
24
25
  segments,
26
+ largeSegments,
25
27
  impressions: new ImpressionsCacheInMemory(impressionsQueueSize),
26
28
  impressionCounts: impressionsMode !== DEBUG ? new ImpressionCountsCacheInMemory() : undefined,
27
29
  events: new EventsCacheInMemory(eventsQueueSize),
@@ -32,6 +34,7 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
32
34
  destroy() {
33
35
  this.splits.clear();
34
36
  this.segments.clear();
37
+ this.largeSegments.clear();
35
38
  this.impressions.clear();
36
39
  this.impressionCounts && this.impressionCounts.clear();
37
40
  this.events.clear();
@@ -43,6 +46,7 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
43
46
  return {
44
47
  splits: this.splits,
45
48
  segments: new MySegmentsCacheInMemory(),
49
+ largeSegments: new MySegmentsCacheInMemory(),
46
50
  impressions: this.impressions,
47
51
  impressionCounts: this.impressionCounts,
48
52
  events: this.events,
@@ -52,6 +56,7 @@ export function InMemoryStorageCSFactory(params: IStorageFactoryParams): IStorag
52
56
  destroy() {
53
57
  this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
54
58
  this.segments.clear();
59
+ this.largeSegments.clear();
55
60
  }
56
61
  };
57
62
  },
@@ -1,7 +1,8 @@
1
1
  import { ISplit, ISplitFiltersValidation } from '../../dtos/types';
2
- import { AbstractSplitsCacheSync, usesSegments } from '../AbstractSplitsCacheSync';
2
+ import { AbstractSplitsCacheSync, usesMatcher } from '../AbstractSplitsCacheSync';
3
3
  import { isFiniteNumber } from '../../utils/lang';
4
4
  import { ISet, _Set } from '../../utils/lang/sets';
5
+ import { IN_LARGE_SEGMENT, IN_SEGMENT } from '../../utils/constants';
5
6
 
6
7
  /**
7
8
  * Default ISplitsCacheSync implementation that stores split definitions in memory.
@@ -13,7 +14,8 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
13
14
  private splitsCache: Record<string, ISplit> = {};
14
15
  private ttCache: Record<string, number> = {};
15
16
  private changeNumber: number = -1;
16
- private splitsWithSegmentsCount: number = 0;
17
+ private segmentsCount: number = 0;
18
+ private largeSegmentsCount: number = 0;
17
19
  private flagSetsCache: Record<string, ISet<string>> = {};
18
20
 
19
21
  constructor(splitFiltersValidation?: ISplitFiltersValidation) {
@@ -25,7 +27,8 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
25
27
  this.splitsCache = {};
26
28
  this.ttCache = {};
27
29
  this.changeNumber = -1;
28
- this.splitsWithSegmentsCount = 0;
30
+ this.segmentsCount = 0;
31
+ this.largeSegmentsCount = 0;
29
32
  }
30
33
 
31
34
  addSplit(name: string, split: ISplit): boolean {
@@ -38,9 +41,9 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
38
41
 
39
42
  this.removeFromFlagSets(previousSplit.name, previousSplit.sets);
40
43
 
41
- if (usesSegments(previousSplit)) { // Substract from segments count for the previous version of this Split.
42
- this.splitsWithSegmentsCount--;
43
- }
44
+ // Substract from segments count for the previous version of this Split.
45
+ if (usesMatcher(previousSplit, IN_SEGMENT)) this.segmentsCount--;
46
+ if (usesMatcher(previousSplit, IN_LARGE_SEGMENT)) this.largeSegmentsCount--;
44
47
  }
45
48
 
46
49
  if (split) {
@@ -52,7 +55,8 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
52
55
  this.addToFlagSets(split);
53
56
 
54
57
  // Add to segments count for the new version of the Split
55
- if (usesSegments(split)) this.splitsWithSegmentsCount++;
58
+ if (usesMatcher(split, IN_SEGMENT)) this.segmentsCount++;
59
+ if (usesMatcher(split, IN_LARGE_SEGMENT)) this.largeSegmentsCount++;
56
60
 
57
61
  return true;
58
62
  } else {
@@ -72,7 +76,8 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
72
76
  this.removeFromFlagSets(split.name, split.sets);
73
77
 
74
78
  // Update the segments count.
75
- if (usesSegments(split)) this.splitsWithSegmentsCount--;
79
+ if (usesMatcher(split, IN_SEGMENT)) this.segmentsCount--;
80
+ if (usesMatcher(split, IN_LARGE_SEGMENT)) this.largeSegmentsCount--;
76
81
 
77
82
  return true;
78
83
  } else {
@@ -101,8 +106,8 @@ export class SplitsCacheInMemory extends AbstractSplitsCacheSync {
101
106
  return isFiniteNumber(this.ttCache[trafficType]) && this.ttCache[trafficType] > 0;
102
107
  }
103
108
 
104
- usesSegments(): boolean {
105
- return this.getChangeNumber() === -1 || this.splitsWithSegmentsCount > 0;
109
+ usesMatcher(matcherType: string): boolean {
110
+ return this.getChangeNumber() === -1 || (matcherType === IN_SEGMENT ? this.segmentsCount > 0 : this.largeSegmentsCount > 0);
106
111
  }
107
112
 
108
113
  getNamesByFlagSets(flagSets: string[]): ISet<string>[] {
@@ -1,4 +1,4 @@
1
- import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../../sync/submitters/types';
1
+ import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies, TelemetryUsageStatsPayload, UpdatesFromSSEEnum, UpdatesFromSSE } from '../../sync/submitters/types';
2
2
  import { DEDUPED, DROPPED, LOCALHOST_MODE, QUEUED } from '../../utils/constants';
3
3
  import { findLatencyIndex } from '../findLatencyIndex';
4
4
  import { ISegmentsCacheSync, ISplitsCacheSync, IStorageFactoryParams, ITelemetryCacheSync } from '../types';
@@ -25,7 +25,7 @@ export function shouldRecordTelemetry({ settings }: IStorageFactoryParams) {
25
25
 
26
26
  export class TelemetryCacheInMemory implements ITelemetryCacheSync {
27
27
 
28
- constructor(private splits?: ISplitsCacheSync, private segments?: ISegmentsCacheSync) { }
28
+ constructor(private splits?: ISplitsCacheSync, private segments?: ISegmentsCacheSync, private largeSegments?: ISegmentsCacheSync) { }
29
29
 
30
30
  // isEmpty flag
31
31
  private e = true;
@@ -51,6 +51,8 @@ export class TelemetryCacheInMemory implements ITelemetryCacheSync {
51
51
  spC: this.splits && this.splits.getSplitNames().length,
52
52
  seC: this.segments && this.segments.getRegisteredSegments().length,
53
53
  skC: this.segments && this.segments.getKeysCount(),
54
+ lseC: this.largeSegments && this.largeSegments.getRegisteredSegments().length,
55
+ lskC: this.largeSegments && this.largeSegments.getKeysCount(),
54
56
  sL: this.getSessionLength(),
55
57
  eQ: this.getEventStats(QUEUED),
56
58
  eD: this.getEventStats(DROPPED),
@@ -245,22 +247,16 @@ export class TelemetryCacheInMemory implements ITelemetryCacheSync {
245
247
  this.e = false;
246
248
  }
247
249
 
248
- private updatesFromSSE = {
249
- sp: 0,
250
- ms: 0
251
- };
250
+ private updatesFromSSE: UpdatesFromSSE = {};
252
251
 
253
252
  popUpdatesFromSSE() {
254
253
  const result = this.updatesFromSSE;
255
- this.updatesFromSSE = {
256
- sp: 0,
257
- ms: 0,
258
- };
254
+ this.updatesFromSSE = {};
259
255
  return result;
260
256
  }
261
257
 
262
258
  recordUpdatesFromSSE(type: UpdatesFromSSEEnum) {
263
- this.updatesFromSSE[type]++;
259
+ this.updatesFromSSE[type] = (this.updatesFromSSE[type] || 0) + 1;
264
260
  this.e = false;
265
261
  }
266
262
 
@@ -205,7 +205,7 @@ export interface ISplitsCacheBase {
205
205
  // should never reject or throw an exception. Instead return true by default, asssuming the TT might exist.
206
206
  trafficTypeExists(trafficType: string): MaybeThenable<boolean>,
207
207
  // only for Client-Side
208
- usesSegments(): MaybeThenable<boolean>,
208
+ usesMatcher(matcherType: string): MaybeThenable<boolean>,
209
209
  clear(): MaybeThenable<boolean | void>,
210
210
  // should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE.
211
211
  checkCache(): MaybeThenable<boolean>,
@@ -223,7 +223,7 @@ export interface ISplitsCacheSync extends ISplitsCacheBase {
223
223
  getAll(): ISplit[],
224
224
  getSplitNames(): string[],
225
225
  trafficTypeExists(trafficType: string): boolean,
226
- usesSegments(): boolean,
226
+ usesMatcher(matcherType: string): boolean,
227
227
  clear(): void,
228
228
  checkCache(): boolean,
229
229
  killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean,
@@ -240,7 +240,7 @@ export interface ISplitsCacheAsync extends ISplitsCacheBase {
240
240
  getAll(): Promise<ISplit[]>,
241
241
  getSplitNames(): Promise<string[]>,
242
242
  trafficTypeExists(trafficType: string): Promise<boolean>,
243
- usesSegments(): Promise<boolean>,
243
+ usesMatcher(matcherType: string): Promise<boolean>,
244
244
  clear(): Promise<boolean | void>,
245
245
  checkCache(): Promise<boolean>,
246
246
  killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise<boolean>,
@@ -477,7 +477,9 @@ export interface IStorageSync extends IStorageBase<
477
477
  IEventsCacheSync,
478
478
  ITelemetryCacheSync,
479
479
  IUniqueKeysCacheSync
480
- > { }
480
+ > {
481
+ largeSegments?: ISegmentsCacheSync,
482
+ }
481
483
 
482
484
  export interface IStorageAsync extends IStorageBase<
483
485
  ISplitsCacheAsync,
@@ -6,8 +6,9 @@ import { mySegmentsSyncTaskFactory } from './syncTasks/mySegmentsSyncTask';
6
6
  import { splitsSyncTaskFactory } from './syncTasks/splitsSyncTask';
7
7
  import { getMatching } from '../../utils/key';
8
8
  import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../../readiness/constants';
9
- import { POLLING_SMART_PAUSING, POLLING_START, POLLING_STOP } from '../../logger/constants';
9
+ import { POLLING_START, POLLING_STOP } from '../../logger/constants';
10
10
  import { ISdkFactoryContextSync } from '../../sdkFactory/types';
11
+ import { IN_LARGE_SEGMENT, IN_SEGMENT } from '../../utils/constants';
11
12
 
12
13
  /**
13
14
  * Expose start / stop mechanism for polling data from services.
@@ -22,62 +23,95 @@ export function pollingManagerCSFactory(
22
23
 
23
24
  const splitsSyncTask = splitsSyncTaskFactory(splitApi.fetchSplitChanges, storage, readiness, settings, true);
24
25
 
25
- // Map of matching keys to their corresponding MySegmentsSyncTask.
26
- const mySegmentsSyncTasks: Record<string, IMySegmentsSyncTask> = {};
26
+ // Map of matching keys to their corresponding MySegmentsSyncTask for segments and large segments.
27
+ const mySegmentsSyncTasks: Record<string, { msSyncTask: IMySegmentsSyncTask, mlsSyncTask?: IMySegmentsSyncTask }> = {};
27
28
 
28
29
  const matchingKey = getMatching(settings.core.key);
29
- const mySegmentsSyncTask = add(matchingKey, readiness, storage);
30
+ const { msSyncTask, mlsSyncTask } = add(matchingKey, readiness, storage);
30
31
 
31
32
  function startMySegmentsSyncTasks() {
32
- forOwn(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
33
- mySegmentsSyncTask.start();
33
+ const splitsHaveSegments = storage.splits.usesMatcher(IN_SEGMENT);
34
+ const splitsHaveLargeSegments = storage.splits.usesMatcher(IN_LARGE_SEGMENT);
35
+
36
+ forOwn(mySegmentsSyncTasks, ({ msSyncTask, mlsSyncTask }) => {
37
+ if (splitsHaveSegments) msSyncTask.start();
38
+ else msSyncTask.stop();
39
+
40
+ if (mlsSyncTask) {
41
+ if (splitsHaveLargeSegments) mlsSyncTask.start();
42
+ else mlsSyncTask.stop();
43
+ }
34
44
  });
35
45
  }
36
46
 
37
47
  function stopMySegmentsSyncTasks() {
38
- forOwn(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
39
- if (mySegmentsSyncTask.isRunning()) mySegmentsSyncTask.stop();
48
+ forOwn(mySegmentsSyncTasks, ({ msSyncTask, mlsSyncTask }) => {
49
+ msSyncTask.stop();
50
+ mlsSyncTask && mlsSyncTask.stop();
40
51
  });
41
52
  }
42
53
 
43
54
  // smart pausing
44
55
  readiness.splits.on(SDK_SPLITS_ARRIVED, () => {
45
- if (!splitsSyncTask.isRunning()) return; // noop if not doing polling
46
- const splitsHaveSegments = storage.splits.usesSegments();
47
- if (splitsHaveSegments !== mySegmentsSyncTask.isRunning()) {
48
- log.info(POLLING_SMART_PAUSING, [splitsHaveSegments ? 'ON' : 'OFF']);
49
- if (splitsHaveSegments) {
50
- startMySegmentsSyncTasks();
51
- } else {
52
- stopMySegmentsSyncTasks();
53
- }
54
- }
56
+ // smart pausing of mySegments polling
57
+ if (splitsSyncTask.isRunning()) startMySegmentsSyncTasks();
55
58
  });
56
59
 
57
60
  function add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync) {
58
- const mySegmentsSyncTask = mySegmentsSyncTaskFactory(splitApi.fetchMySegments, storage, readiness, settings, matchingKey);
61
+ const msSyncTask = mySegmentsSyncTaskFactory(
62
+ splitApi.fetchMySegments,
63
+ storage.segments,
64
+ () => {
65
+ if (storage.splits.usesMatcher(IN_SEGMENT)) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
66
+ },
67
+ settings,
68
+ matchingKey,
69
+ settings.scheduler.segmentsRefreshRate
70
+ );
71
+
72
+ let mlsSyncTask;
73
+ if (settings.sync.largeSegmentsEnabled) {
74
+ mlsSyncTask = mySegmentsSyncTaskFactory(
75
+ splitApi.fetchMyLargeSegments,
76
+ storage.largeSegments!,
77
+ () => {
78
+ if (readiness.largeSegments && storage.splits.usesMatcher(IN_LARGE_SEGMENT)) readiness.largeSegments.emit(SDK_SEGMENTS_ARRIVED);
79
+ },
80
+ settings,
81
+ matchingKey,
82
+ settings.scheduler.largeSegmentsRefreshRate
83
+ );
84
+ }
59
85
 
60
86
  // smart ready
61
87
  function smartReady() {
62
- if (!readiness.isReady() && !storage.splits.usesSegments()) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
88
+ if (!readiness.isReady()) {
89
+ if (!storage.splits.usesMatcher(IN_SEGMENT)) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
90
+ if (readiness.largeSegments && !storage.splits.usesMatcher(IN_LARGE_SEGMENT)) readiness.largeSegments.emit(SDK_SEGMENTS_ARRIVED);
91
+ }
63
92
  }
64
- if (!storage.splits.usesSegments()) setTimeout(smartReady, 0);
93
+ if (!storage.splits.usesMatcher(IN_SEGMENT) && !storage.splits.usesMatcher(IN_LARGE_SEGMENT)) setTimeout(smartReady, 0);
65
94
  else readiness.splits.once(SDK_SPLITS_ARRIVED, smartReady);
66
95
 
67
- mySegmentsSyncTasks[matchingKey] = mySegmentsSyncTask;
68
- return mySegmentsSyncTask;
96
+ mySegmentsSyncTasks[matchingKey] = { msSyncTask: msSyncTask, mlsSyncTask: mlsSyncTask };
97
+
98
+ return {
99
+ msSyncTask,
100
+ mlsSyncTask
101
+ };
69
102
  }
70
103
 
71
104
  return {
72
105
  splitsSyncTask,
73
- segmentsSyncTask: mySegmentsSyncTask,
106
+ segmentsSyncTask: msSyncTask,
107
+ largeSegmentsSyncTask: mlsSyncTask,
74
108
 
75
109
  // Start periodic fetching (polling)
76
110
  start() {
77
111
  log.info(POLLING_START);
78
112
 
79
113
  splitsSyncTask.start();
80
- if (storage.splits.usesSegments()) startMySegmentsSyncTasks();
114
+ startMySegmentsSyncTasks();
81
115
  },
82
116
 
83
117
  // Stop periodic fetching (polling)
@@ -94,8 +128,9 @@ export function pollingManagerCSFactory(
94
128
  // fetch splits and segments
95
129
  syncAll() {
96
130
  const promises = [splitsSyncTask.execute()];
97
- forOwn(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
98
- promises.push(mySegmentsSyncTask.execute());
131
+ forOwn(mySegmentsSyncTasks, function ({ msSyncTask, mlsSyncTask }) {
132
+ promises.push(msSyncTask.execute());
133
+ mlsSyncTask && promises.push(mlsSyncTask.execute());
99
134
  });
100
135
  return Promise.all(promises);
101
136
  },
@@ -1,5 +1,4 @@
1
- import { IStorageSync } from '../../../storages/types';
2
- import { IReadinessManager } from '../../../readiness/types';
1
+ import { ISegmentsCacheSync } from '../../../storages/types';
3
2
  import { syncTaskFactory } from '../../syncTask';
4
3
  import { IMySegmentsSyncTask } from '../types';
5
4
  import { IFetchMySegments } from '../../../services/types';
@@ -12,24 +11,24 @@ import { mySegmentsUpdaterFactory } from '../updaters/mySegmentsUpdater';
12
11
  */
13
12
  export function mySegmentsSyncTaskFactory(
14
13
  fetchMySegments: IFetchMySegments,
15
- storage: IStorageSync,
16
- readiness: IReadinessManager,
14
+ mySegmentsCache: ISegmentsCacheSync,
15
+ notifyUpdate: () => void,
17
16
  settings: ISettings,
18
- matchingKey: string
17
+ matchingKey: string,
18
+ segmentsRefreshRate: number
19
19
  ): IMySegmentsSyncTask {
20
20
  return syncTaskFactory(
21
21
  settings.log,
22
22
  mySegmentsUpdaterFactory(
23
23
  settings.log,
24
24
  mySegmentsFetcherFactory(fetchMySegments),
25
- storage.splits,
26
- storage.segments,
27
- readiness.segments,
25
+ mySegmentsCache,
26
+ notifyUpdate,
28
27
  settings.startup.requestTimeoutBeforeReady,
29
28
  settings.startup.retriesOnFailureBeforeReady,
30
29
  matchingKey
31
30
  ),
32
- settings.scheduler.segmentsRefreshRate,
31
+ segmentsRefreshRate,
33
32
  'mySegmentsUpdater',
34
33
  );
35
34
  }
@@ -14,19 +14,20 @@ export type MySegmentsData = string[] | {
14
14
  add: boolean
15
15
  }
16
16
 
17
- export interface IMySegmentsSyncTask extends ISyncTask<[segmentsData?: MySegmentsData, noCache?: boolean], boolean> { }
17
+ export interface IMySegmentsSyncTask extends ISyncTask<[segmentsData?: MySegmentsData, noCache?: boolean, delay?: number], boolean> { }
18
18
 
19
19
  export interface IPollingManager extends ITask {
20
20
  syncAll(): Promise<any>
21
21
  splitsSyncTask: ISplitsSyncTask
22
22
  segmentsSyncTask: ISyncTask
23
+ largeSegmentsSyncTask?: ISyncTask
23
24
  }
24
25
 
25
26
  /**
26
27
  * PollingManager for client-side with support for multiple clients
27
28
  */
28
29
  export interface IPollingManagerCS extends IPollingManager {
29
- add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync): IMySegmentsSyncTask
30
+ add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync): { msSyncTask: IMySegmentsSyncTask, mlsSyncTask?: IMySegmentsSyncTask }
30
31
  remove(matchingKey: string): void;
31
- get(matchingKey: string): IMySegmentsSyncTask | undefined
32
+ get(matchingKey: string): { msSyncTask: IMySegmentsSyncTask, mlsSyncTask?: IMySegmentsSyncTask } | undefined
32
33
  }
@@ -1,13 +1,11 @@
1
1
  import { IMySegmentsFetcher } from '../fetchers/types';
2
- import { ISegmentsCacheSync, ISplitsCacheSync } from '../../../storages/types';
3
- import { ISegmentsEventEmitter } from '../../../readiness/types';
2
+ import { ISegmentsCacheSync } from '../../../storages/types';
4
3
  import { timeout } from '../../../utils/promise/timeout';
5
- import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
6
4
  import { ILogger } from '../../../logger/types';
7
5
  import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants';
8
6
  import { MySegmentsData } from '../types';
9
7
 
10
- type IMySegmentsUpdater = (segmentList?: string[], noCache?: boolean) => Promise<boolean>
8
+ type IMySegmentsUpdater = (segmentList?: MySegmentsData, noCache?: boolean) => Promise<boolean>
11
9
 
12
10
  /**
13
11
  * factory of MySegments updater, a task that:
@@ -18,9 +16,8 @@ type IMySegmentsUpdater = (segmentList?: string[], noCache?: boolean) => Promise
18
16
  export function mySegmentsUpdaterFactory(
19
17
  log: ILogger,
20
18
  mySegmentsFetcher: IMySegmentsFetcher,
21
- splitsCache: ISplitsCacheSync,
22
19
  mySegmentsCache: ISegmentsCacheSync,
23
- segmentsEventEmitter: ISegmentsEventEmitter,
20
+ notifyUpdate: () => void,
24
21
  requestTimeoutBeforeReady: number,
25
22
  retriesOnFailureBeforeReady: number,
26
23
  matchingKey: string
@@ -55,9 +52,9 @@ export function mySegmentsUpdaterFactory(
55
52
  }
56
53
 
57
54
  // Notify update if required
58
- if (splitsCache.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
55
+ if (shouldNotifyUpdate || readyOnAlreadyExistentState) {
59
56
  readyOnAlreadyExistentState = false;
60
- segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
57
+ notifyUpdate();
61
58
  }
62
59
  }
63
60
 
@@ -97,8 +94,14 @@ export function mySegmentsUpdaterFactory(
97
94
  * (3) or `undefined`, for which the updater will fetch mySegments in order to sync the storage.
98
95
  * @param {boolean | undefined} noCache true to revalidate data to fetch
99
96
  */
100
- return function mySegmentsUpdater(segmentsData?: MySegmentsData, noCache?: boolean) {
101
- return _mySegmentsUpdater(0, segmentsData, noCache);
97
+ return function mySegmentsUpdater(segmentsData?: MySegmentsData, noCache?: boolean, delay?: number) {
98
+ return delay ?
99
+ new Promise(res => {
100
+ setTimeout(() => {
101
+ _mySegmentsUpdater(0, segmentsData, noCache).then(res);
102
+ }, delay);
103
+ }) :
104
+ _mySegmentsUpdater(0, segmentsData, noCache);
102
105
  };
103
106
 
104
107
  }
@@ -8,6 +8,7 @@ import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/
8
8
  import { ILogger } from '../../../logger/types';
9
9
  import { SYNC_SPLITS_FETCH, SYNC_SPLITS_NEW, SYNC_SPLITS_REMOVED, SYNC_SPLITS_SEGMENTS, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
10
10
  import { startsWith } from '../../../utils/lang';
11
+ import { IN_SEGMENT } from '../../../utils/constants';
11
12
 
12
13
  type ISplitChangesUpdater = (noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }) => Promise<boolean>
13
14
 
@@ -33,7 +34,7 @@ export function parseSegments({ conditions }: ISplit): ISet<string> {
33
34
  const matchers = conditions[i].matcherGroup.matchers;
34
35
 
35
36
  matchers.forEach(matcher => {
36
- if (matcher.matcherType === 'IN_SEGMENT') segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
37
+ if (matcher.matcherType === IN_SEGMENT) segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
37
38
  });
38
39
  }
39
40
 
@@ -54,7 +55,7 @@ interface ISplitMutations {
54
55
  * @param filters splitFiltersValidation bySet | byName
55
56
  */
56
57
  function matchFilters(featureFlag: ISplit, filters: ISplitFiltersValidation) {
57
- const { bySet: setsFilter, byName: namesFilter, byPrefix: prefixFilter} = filters.groupedFilters;
58
+ const { bySet: setsFilter, byName: namesFilter, byPrefix: prefixFilter } = filters.groupedFilters;
58
59
  if (setsFilter.length > 0) return featureFlag.sets && featureFlag.sets.some((featureFlagSet: string) => setsFilter.indexOf(featureFlagSet) > -1);
59
60
 
60
61
  const namesFilterConfigured = namesFilter.length > 0;
@@ -129,7 +130,7 @@ export function splitChangesUpdaterFactory(
129
130
 
130
131
  /** Returns true if at least one split was updated */
131
132
  function isThereUpdate(flagsChange: [boolean | void, void | boolean[], void | boolean[], boolean | void] | [any, any, any]) {
132
- const [, added, removed, ] = flagsChange;
133
+ const [, added, removed] = flagsChange;
133
134
  // There is at least one added or modified feature flag
134
135
  if (added && added.some((update: boolean) => update)) return true;
135
136
  // There is at least one removed feature flag
@@ -1,6 +1,6 @@
1
1
  import { errorParser, messageParser } from './NotificationParser';
2
2
  import { notificationKeeperFactory } from './NotificationKeeper';
3
- import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE } from '../constants';
3
+ import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MY_LARGE_SEGMENTS_UPDATE } from '../constants';
4
4
  import { IPushEventEmitter } from '../types';
5
5
  import { ISseEventHandler } from '../SSEClient/types';
6
6
  import { INotificationError, INotificationMessage } from './types';
@@ -83,6 +83,7 @@ export function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventEmitter,
83
83
  case SPLIT_UPDATE:
84
84
  case SEGMENT_UPDATE:
85
85
  case MY_SEGMENTS_UPDATE_V2:
86
+ case MY_LARGE_SEGMENTS_UPDATE:
86
87
  case SPLIT_KILL:
87
88
  pushEmitter.emit(parsedData.type, parsedData);
88
89
  break;