Skip to content

Commit 590daa2

Browse files
Separate getRolloutPlan and setRolloutPlan for bundle size reduction
1 parent 9ddadd6 commit 590daa2

File tree

9 files changed

+169
-163
lines changed

9 files changed

+169
-163
lines changed

src/sdkClient/sdkClientMethodCS.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { RETRIEVE_CLIENT_DEFAULT, NEW_SHARED_CLIENT, RETRIEVE_CLIENT_EXISTING, L
99
import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
1010
import { ISdkFactoryContext } from '../sdkFactory/types';
1111
import { buildInstanceId } from './identity';
12-
import { setRolloutPlan } from '../storages/dataLoader';
12+
import { setRolloutPlan } from '../storages/setRolloutPlan';
1313
import { ISegmentsCacheSync } from '../storages/types';
1414

1515
/**

src/sdkFactory/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { strategyOptimizedFactory } from '../trackers/strategy/strategyOptimized
1414
import { strategyNoneFactory } from '../trackers/strategy/strategyNone';
1515
import { uniqueKeysTrackerFactory } from '../trackers/uniqueKeysTracker';
1616
import { DEBUG, OPTIMIZED } from '../utils/constants';
17-
import { setRolloutPlan } from '../storages/dataLoader';
17+
import { setRolloutPlan } from '../storages/setRolloutPlan';
1818
import { IStorageSync } from '../storages/types';
1919
import { getMatching } from '../utils/key';
2020

src/storages/__tests__/dataLoader.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { fullSettings } from '../../utils/settingsValidation/__tests__/settings.
44
import { loggerMock } from '../../logger/__tests__/sdkLogger.mock';
55
import { IRBSegment, ISplit } from '../../dtos/types';
66

7-
import { validateRolloutPlan, setRolloutPlan, getRolloutPlan } from '../dataLoader';
7+
import { validateRolloutPlan, setRolloutPlan } from '../setRolloutPlan';
8+
import { getRolloutPlan } from '../getRolloutPlan';
89

910
const otherKey = 'otherKey';
1011
const expectedRolloutPlan = {

src/storages/dataLoader.ts

Lines changed: 0 additions & 157 deletions
This file was deleted.

src/storages/getRolloutPlan.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import SplitIO from '../../types/splitio';
2+
import { IStorageSync } from './types';
3+
import { setToArray } from '../utils/lang/sets';
4+
import { getMatching } from '../utils/key';
5+
import { ILogger } from '../logger/types';
6+
import { RolloutPlan } from './types';
7+
import { IMembershipsResponse, IMySegmentsResponse } from '../dtos/types';
8+
9+
/**
10+
* Gets the rollout plan snapshot from the given synchronous storage.
11+
* If `keys` are provided, the memberships for those keys is returned, to protect segments data.
12+
* Otherwise, the segments data is returned.
13+
*/
14+
export function getRolloutPlan(log: ILogger, storage: IStorageSync, options: SplitIO.RolloutPlanOptions = {}): RolloutPlan {
15+
16+
const { keys, exposeSegments } = options;
17+
const { splits, segments, rbSegments } = storage;
18+
19+
log.debug(`storage: get feature flags${keys ? `, and memberships for keys ${keys}` : ''}${exposeSegments ? ', and segments' : ''}`);
20+
21+
return {
22+
splitChanges: {
23+
ff: {
24+
t: splits.getChangeNumber(),
25+
s: -1,
26+
d: splits.getAll(),
27+
},
28+
rbs: {
29+
t: rbSegments.getChangeNumber(),
30+
s: -1,
31+
d: rbSegments.getAll(),
32+
}
33+
},
34+
segmentChanges: exposeSegments ? // @ts-ignore accessing private prop
35+
Object.keys(segments.segmentCache).map(segmentName => ({
36+
name: segmentName, // @ts-ignore
37+
added: setToArray(segments.segmentCache[segmentName] as Set<string>),
38+
removed: [],
39+
till: segments.getChangeNumber(segmentName)!
40+
})) :
41+
undefined,
42+
memberships: keys ?
43+
keys.reduce<Record<string, IMembershipsResponse>>((prev, key) => {
44+
const matchingKey = getMatching(key);
45+
if (storage.shared) { // Client-side segments
46+
const sharedStorage = storage.shared(matchingKey);
47+
prev[matchingKey] = {
48+
ms: { // @ts-ignore
49+
k: Object.keys(sharedStorage.segments.segmentCache).map(segmentName => ({ n: segmentName })),
50+
},
51+
ls: sharedStorage.largeSegments ? { // @ts-ignore
52+
k: Object.keys(sharedStorage.largeSegments.segmentCache).map(segmentName => ({ n: segmentName })),
53+
} : undefined
54+
};
55+
} else { // Server-side segments
56+
prev[matchingKey] = {
57+
ms: { // @ts-ignore
58+
k: Object.keys(storage.segments.segmentCache).reduce<IMySegmentsResponse['k']>((prev, segmentName) => { // @ts-ignore
59+
return storage.segments.segmentCache[segmentName].has(matchingKey) ?
60+
prev!.concat({ n: segmentName }) :
61+
prev;
62+
}, [])
63+
},
64+
ls: {
65+
k: []
66+
}
67+
};
68+
}
69+
return prev;
70+
}, {}) :
71+
undefined
72+
};
73+
}

src/storages/setRolloutPlan.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import SplitIO from '../../types/splitio';
2+
import { IRBSegmentsCacheSync, ISegmentsCacheSync, ISplitsCacheSync } from './types';
3+
import { ILogger } from '../logger/types';
4+
import { isObject } from '../utils/lang';
5+
import { isConsumerMode } from '../utils/settingsValidation/mode';
6+
import { RolloutPlan } from './types';
7+
8+
/**
9+
* Validates if the given rollout plan is valid.
10+
*/
11+
export function validateRolloutPlan(log: ILogger, settings: SplitIO.ISettings): RolloutPlan | undefined {
12+
const { mode, initialRolloutPlan } = settings;
13+
14+
if (isConsumerMode(mode)) {
15+
log.warn('storage: initial rollout plan is ignored in consumer mode');
16+
return;
17+
}
18+
19+
if (isObject(initialRolloutPlan) && isObject((initialRolloutPlan as any).splitChanges)) return initialRolloutPlan as RolloutPlan;
20+
21+
log.error('storage: invalid rollout plan provided');
22+
return;
23+
}
24+
25+
/**
26+
* Sets the given synchronous storage with the provided rollout plan snapshot.
27+
* If `matchingKey` is provided, the storage is handled as a client-side storage (segments and largeSegments are instances of MySegmentsCache).
28+
* Otherwise, the storage is handled as a server-side storage (segments is an instance of SegmentsCache).
29+
*/
30+
export function setRolloutPlan(log: ILogger, rolloutPlan: RolloutPlan, storage: { splits?: ISplitsCacheSync, rbSegments?: IRBSegmentsCacheSync, segments: ISegmentsCacheSync, largeSegments?: ISegmentsCacheSync }, matchingKey?: string) {
31+
const { splits, rbSegments, segments, largeSegments } = storage;
32+
const { splitChanges: { ff, rbs } } = rolloutPlan;
33+
34+
log.debug(`storage: set feature flags and segments${matchingKey ? ` for key ${matchingKey}` : ''}`);
35+
36+
if (splits && ff) {
37+
splits.clear();
38+
splits.update(ff.d, [], ff.t);
39+
}
40+
41+
if (rbSegments && rbs) {
42+
rbSegments.clear();
43+
rbSegments.update(rbs.d, [], rbs.t);
44+
}
45+
46+
const segmentChanges = rolloutPlan.segmentChanges;
47+
if (matchingKey) { // add memberships data (client-side)
48+
let memberships = rolloutPlan.memberships && rolloutPlan.memberships[matchingKey];
49+
if (!memberships && segmentChanges) {
50+
memberships = {
51+
ms: {
52+
k: segmentChanges.filter(segment => {
53+
return segment.added.indexOf(matchingKey) > -1;
54+
}).map(segment => ({ n: segment.name }))
55+
}
56+
};
57+
}
58+
59+
if (memberships) {
60+
if (memberships.ms) segments.resetSegments(memberships.ms!);
61+
if (memberships.ls && largeSegments) largeSegments.resetSegments(memberships.ls!);
62+
}
63+
} else { // add segments data (server-side)
64+
if (segmentChanges) {
65+
segments.clear();
66+
segmentChanges.forEach(segment => {
67+
segments.update(segment.name, segment.added, segment.removed, segment.till);
68+
});
69+
}
70+
}
71+
}

src/storages/types.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import SplitIO from '../../types/splitio';
2-
import { MaybeThenable, ISplit, IRBSegment, IMySegmentsResponse } from '../dtos/types';
2+
import { MaybeThenable, ISplit, IRBSegment, IMySegmentsResponse, IMembershipsResponse, ISegmentChangesResponse, ISplitChangesResponse } from '../dtos/types';
33
import { MySegmentsData } from '../sync/polling/types';
44
import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, MultiMethodExceptions, MultiMethodLatencies, MultiConfigs, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent, UniqueKeysPayloadCs, UniqueKeysPayloadSs, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../sync/submitters/types';
55
import { ISettings } from '../types';
@@ -520,3 +520,21 @@ export type IStorageAsyncFactory = SplitIO.StorageAsyncFactory & {
520520
readonly type: SplitIO.StorageType,
521521
(params: IStorageFactoryParams): IStorageAsync
522522
}
523+
524+
export type RolloutPlan = {
525+
/**
526+
* Feature flags and rule-based segments.
527+
*/
528+
splitChanges: ISplitChangesResponse;
529+
/**
530+
* Optional map of matching keys to their memberships.
531+
*/
532+
memberships?: {
533+
[matchingKey: string]: IMembershipsResponse;
534+
};
535+
/**
536+
* Optional list of standard segments.
537+
* This property is ignored if `memberships` is provided.
538+
*/
539+
segmentChanges?: ISegmentChangesResponse[];
540+
};

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import SplitIO from '../types/splitio';
22
import { ISplitFiltersValidation } from './dtos/types';
33
import { ILogger } from './logger/types';
4-
import { RolloutPlan } from './storages/dataLoader';
4+
import { RolloutPlan } from './storages/types';
55

66
/**
77
* SplitIO.ISettings interface extended with private properties for internal use

src/utils/settingsValidation/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ISettingsValidationParams } from './types';
77
import { ISettings } from '../../types';
88
import { validateKey } from '../inputValidation/key';
99
import { ERROR_MIN_CONFIG_PARAM, LOG_PREFIX_CLIENT_INSTANTIATION } from '../../logger/constants';
10-
import { validateRolloutPlan } from '../../storages/dataLoader';
10+
import { validateRolloutPlan } from '../../storages/setRolloutPlan';
1111

1212
// Exported for telemetry
1313
export const base = {

0 commit comments

Comments
 (0)