Skip to content

Commit 134869e

Browse files
Merge pull request #413 from splitio/refactor_usesSegmentsSync
Refactor: fix Type Definition comments and add `usesSegmentsSync` utility function for reusability
2 parents 843952b + 1b77a63 commit 134869e

File tree

13 files changed

+70
-47
lines changed

13 files changed

+70
-47
lines changed

CHANGES.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
- Updated the Redis storage to:
1010
- Avoid lazy require of the `ioredis` dependency when the SDK is initialized, and
1111
- Flag the SDK as ready from cache immediately to allow queueing feature flag evaluations before SDK_READY event is emitted (Reverted in v1.7.0).
12-
- Bugfix - Enhanced HTTP client module to implement timeouts for failing requests that might otherwise remain pending indefinitely on some Fetch API implementations.
12+
- Bugfix - Enhanced HTTP client module to implement timeouts for failing requests that might otherwise remain pending indefinitely on some Fetch API implementations, pausing the SDK synchronization process.
1313

1414
2.2.0 (March 28, 2025)
1515
- Added a new optional argument to the client `getTreatment` methods to allow passing additional evaluation options, such as a map of properties to append to the generated impressions sent to Split backend. Read more in our docs.

package-lock.json

Lines changed: 14 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/logger/messages/error.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const codesError: [number, string][] = [
1414
[c.ERROR_SYNC_OFFLINE_LOADING, c.LOG_PREFIX_SYNC_OFFLINE + 'There was an issue loading the mock feature flags data. No changes will be applied to the current cache. %s'],
1515
[c.ERROR_STREAMING_SSE, c.LOG_PREFIX_SYNC_STREAMING + 'Failed to connect or error on streaming connection, with error message: %s'],
1616
[c.ERROR_STREAMING_AUTH, c.LOG_PREFIX_SYNC_STREAMING + 'Failed to authenticate for streaming. Error: %s.'],
17-
[c.ERROR_HTTP, 'Response status is not OK. Status: %s. URL: %s. Message: %s'],
17+
[c.ERROR_HTTP, 'HTTP request failed with %s. URL: %s. Message: %s'],
1818
// client status
1919
[c.ERROR_CLIENT_LISTENER, 'A listener was added for %s on the SDK, which has already fired and won\'t be emitted again. The callback won\'t be executed.'],
2020
[c.ERROR_CLIENT_DESTROYED, '%s: Client has already been destroyed - no calls possible.'],

src/services/splitHttpClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export function splitHttpClientFactory(settings: ISettings, { getOptions, getFet
7070
}
7171

7272
if (!resp || resp.status !== 403) { // 403's log we'll be handled somewhere else.
73-
log[logErrorsAsInfo ? 'info' : 'error'](ERROR_HTTP, [resp ? resp.status : 'NO_STATUS', url, msg]);
73+
log[logErrorsAsInfo ? 'info' : 'error'](ERROR_HTTP, [resp ? 'status code ' + resp.status : 'no status code', url, msg]);
7474
}
7575

7676
const networkError: NetworkError = new Error(msg);

src/storages/AbstractSplitsCacheSync.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ISplitsCacheSync } from './types';
1+
import { ISplitsCacheSync, IStorageSync } from './types';
22
import { IRBSegment, ISplit } from '../dtos/types';
33
import { objectAssign } from '../utils/lang/objectAssign';
44
import { IN_SEGMENT, IN_LARGE_SEGMENT } from '../utils/constants';
@@ -88,3 +88,7 @@ export function usesSegments(ruleEntity: ISplit | IRBSegment) {
8888

8989
return false;
9090
}
91+
92+
export function usesSegmentsSync(storage: Pick<IStorageSync, 'splits' | 'rbSegments'>) {
93+
return storage.splits.usesSegments() || storage.rbSegments.usesSegments();
94+
}

src/storages/inLocalStorage/__tests__/SplitsCacheInLocal.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ test('SPLITS CACHE / LocalStorage / flag set cache tests', () => {
173173
], [], -1);
174174
cache.addSplit(featureFlagWithEmptyFS);
175175

176+
// Adding an existing FF should not affect the cache
177+
cache.update([featureFlagTwo], [], -1);
178+
176179
expect(cache.getNamesByFlagSets(['o'])).toEqual([new Set(['ff_one', 'ff_two'])]);
177180
expect(cache.getNamesByFlagSets(['n'])).toEqual([new Set(['ff_one'])]);
178181
expect(cache.getNamesByFlagSets(['e'])).toEqual([new Set(['ff_one', 'ff_three'])]);

src/storages/inMemory/__tests__/SplitsCacheInMemory.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ test('SPLITS CACHE / In Memory / flag set cache tests', () => {
135135
], [], -1);
136136
cache.addSplit(featureFlagWithEmptyFS);
137137

138+
// Adding an existing FF should not affect the cache
139+
cache.update([featureFlagTwo], [], -1);
140+
138141
expect(cache.getNamesByFlagSets(['o'])).toEqual([new Set(['ff_one', 'ff_two'])]);
139142
expect(cache.getNamesByFlagSets(['n'])).toEqual([new Set(['ff_one'])]);
140143
expect(cache.getNamesByFlagSets(['e'])).toEqual([new Set(['ff_one', 'ff_three'])]);

src/sync/polling/pollingManagerCS.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { getMatching } from '../../utils/key';
88
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../../readiness/constants';
99
import { POLLING_SMART_PAUSING, POLLING_START, POLLING_STOP } from '../../logger/constants';
1010
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
11+
import { usesSegmentsSync } from '../../storages/AbstractSplitsCacheSync';
1112

1213
/**
1314
* Expose start / stop mechanism for polling data from services.
@@ -43,7 +44,7 @@ export function pollingManagerCSFactory(
4344
// smart pausing
4445
readiness.splits.on(SDK_SPLITS_ARRIVED, () => {
4546
if (!splitsSyncTask.isRunning()) return; // noop if not doing polling
46-
const usingSegments = storage.splits.usesSegments() || storage.rbSegments.usesSegments();
47+
const usingSegments = usesSegmentsSync(storage);
4748
if (usingSegments !== mySegmentsSyncTask.isRunning()) {
4849
log.info(POLLING_SMART_PAUSING, [usingSegments ? 'ON' : 'OFF']);
4950
if (usingSegments) {
@@ -59,9 +60,9 @@ export function pollingManagerCSFactory(
5960

6061
// smart ready
6162
function smartReady() {
62-
if (!readiness.isReady() && !storage.splits.usesSegments() && !storage.rbSegments.usesSegments()) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
63+
if (!readiness.isReady() && !usesSegmentsSync(storage)) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
6364
}
64-
if (!storage.splits.usesSegments() && !storage.rbSegments.usesSegments()) setTimeout(smartReady, 0);
65+
if (!usesSegmentsSync(storage)) setTimeout(smartReady, 0);
6566
else readiness.splits.once(SDK_SPLITS_ARRIVED, smartReady);
6667

6768
mySegmentsSyncTasks[matchingKey] = mySegmentsSyncTask;
@@ -77,7 +78,7 @@ export function pollingManagerCSFactory(
7778
log.info(POLLING_START);
7879

7980
splitsSyncTask.start();
80-
if (storage.splits.usesSegments() || storage.rbSegments.usesSegments()) startMySegmentsSyncTasks();
81+
if (usesSegmentsSync(storage)) startMySegmentsSyncTasks();
8182
},
8283

8384
// Stop periodic fetching (polling)

src/sync/polling/updaters/mySegmentsUpdater.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants';
88
import { MySegmentsData } from '../types';
99
import { IMembershipsResponse } from '../../../dtos/types';
1010
import { MEMBERSHIPS_LS_UPDATE } from '../../streaming/constants';
11+
import { usesSegmentsSync } from '../../../storages/AbstractSplitsCacheSync';
1112

1213
type IMySegmentsUpdater = (segmentsData?: MySegmentsData, noCache?: boolean, till?: number) => Promise<boolean>
1314

@@ -27,7 +28,7 @@ export function mySegmentsUpdaterFactory(
2728
matchingKey: string
2829
): IMySegmentsUpdater {
2930

30-
const { splits, rbSegments, segments, largeSegments } = storage;
31+
const { segments, largeSegments } = storage;
3132
let readyOnAlreadyExistentState = true;
3233
let startingUp = true;
3334

@@ -51,7 +52,7 @@ export function mySegmentsUpdaterFactory(
5152
}
5253

5354
// Notify update if required
54-
if ((splits.usesSegments() || rbSegments.usesSegments()) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
55+
if (usesSegmentsSync(storage) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
5556
readyOnAlreadyExistentState = false;
5657
segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
5758
}

src/sync/polling/updaters/splitChangesUpdater.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ interface ISplitMutations<T extends ISplit | IRBSegment> {
5959

6060
/**
6161
* If there are defined filters and one feature flag doesn't match with them, its status is changed to 'ARCHIVE' to avoid storing it
62-
* If there are set filter defined, names filter is ignored
62+
* If there is `bySet` filter, `byName` and `byPrefix` filters are ignored
6363
*
6464
* @param featureFlag - feature flag to be evaluated
6565
* @param filters - splitFiltersValidation bySet | byName

0 commit comments

Comments
 (0)