Skip to content

Commit d59aea5

Browse files
Revert "Revert "Add onReadyFromCacheCb to storage factory params for code cleanup""
This reverts commit 34c4bce.
1 parent e084b77 commit d59aea5

File tree

12 files changed

+21
-75
lines changed

12 files changed

+21
-75
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
2.0.0 (October XX, 2024)
22
- Added support for targeting rules based on large segments.
33
- Added `factory.destroy()` method, which invokes the `destroy` method on all SDK clients created by the factory.
4+
- Updated internal storage factory to emit the SDK_READY_FROM_CACHE event when it corresponds, to clean up the initialization flow.
45
- Updated the handling of timers and async operations by moving them into an `init` factory method to enable lazy initialization of the SDK. This update is intended for the React SDK.
56
- Bugfixing - Fixed an issue with the server-side polling manager that caused dangling timers when the SDK was destroyed before it was ready.
67
- BREAKING CHANGES:

src/sdkFactory/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { IBasicClient, SplitIO } from '../types';
77
import { validateAndTrackApiKey } from '../utils/inputValidation/apiKey';
88
import { createLoggerAPI } from '../logger/sdkLogger';
99
import { NEW_FACTORY, RETRIEVE_MANAGER } from '../logger/constants';
10-
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
10+
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../readiness/constants';
1111
import { objectAssign } from '../utils/lang/objectAssign';
1212
import { strategyDebugFactory } from '../trackers/strategy/strategyDebug';
1313
import { strategyOptimizedFactory } from '../trackers/strategy/strategyOptimized';
@@ -52,6 +52,9 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
5252
readiness.splits.emit(SDK_SPLITS_ARRIVED);
5353
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
5454
},
55+
onReadyFromCacheCb: () => {
56+
readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
57+
}
5558
});
5659
// @TODO add support for dataloader: `if (params.dataLoader) params.dataLoader(storage);`
5760
const clients: Record<string, IBasicClient> = {};

src/storages/AbstractSplitsCacheAsync.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,6 @@ export abstract class AbstractSplitsCacheAsync implements ISplitsCacheAsync {
2828
return Promise.resolve(true);
2929
}
3030

31-
/**
32-
* Check if the splits information is already stored in cache.
33-
* Noop, just keeping the interface. This is used by client-side implementations only.
34-
*/
35-
checkCache(): Promise<boolean> {
36-
return Promise.resolve(false);
37-
}
38-
3931
/**
4032
* Kill `name` split and set `defaultTreatment` and `changeNumber`.
4133
* Used for SPLIT_KILL push notifications.

src/storages/AbstractSplitsCacheSync.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,6 @@ export abstract class AbstractSplitsCacheSync implements ISplitsCacheSync {
4848

4949
abstract clear(): void
5050

51-
/**
52-
* Check if the splits information is already stored in cache. This data can be preloaded.
53-
* It is used as condition to emit SDK_SPLITS_CACHE_LOADED, and then SDK_READY_FROM_CACHE.
54-
*/
55-
checkCache(): boolean {
56-
return false;
57-
}
58-
5951
/**
6052
* Kill `name` split and set `defaultTreatment` and `changeNumber`.
6153
* Used for SPLIT_KILL push notifications.

src/storages/inLocalStorage/SplitsCacheInLocal.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -217,15 +217,6 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
217217
}
218218
}
219219

220-
/**
221-
* Check if the splits information is already stored in browser LocalStorage.
222-
* In this function we could add more code to check if the data is valid.
223-
* @override
224-
*/
225-
checkCache(): boolean {
226-
return this.getChangeNumber() > -1;
227-
}
228-
229220
/**
230221
* Clean Splits cache if its `lastUpdated` timestamp is older than the given `expirationTimestamp`,
231222
*
@@ -250,7 +241,7 @@ export class SplitsCacheInLocal extends AbstractSplitsCacheSync {
250241
this.updateNewFilter = true;
251242

252243
// if there is cache, clear it
253-
if (this.checkCache()) this.clear();
244+
if (this.getChangeNumber() > -1) this.clear();
254245

255246
} catch (e) {
256247
this.log.error(LOG_PREFIX + e);

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

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,10 @@ test('SPLIT CACHE / LocalStorage', () => {
3131
expect(cache.getSplit('lol1')).toEqual(null);
3232
expect(cache.getSplit('lol2')).toEqual(somethingElse);
3333

34-
expect(cache.checkCache()).toBe(false); // checkCache should return false until localstorage has data.
35-
3634
expect(cache.getChangeNumber() === -1).toBe(true);
3735

38-
expect(cache.checkCache()).toBe(false); // checkCache should return false until localstorage has data.
39-
4036
cache.setChangeNumber(123);
4137

42-
expect(cache.checkCache()).toBe(true); // checkCache should return true once localstorage has data.
43-
4438
expect(cache.getChangeNumber() === 123).toBe(true);
4539

4640
});

src/storages/inLocalStorage/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
3636
return InMemoryStorageCSFactory(params);
3737
}
3838

39-
const { settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation } } } = params;
39+
const { onReadyFromCacheCb, settings, settings: { log, scheduler: { impressionsQueueSize, eventsQueueSize, }, sync: { impressionsMode, __splitFiltersValidation } } } = params;
4040
const matchingKey = getMatching(settings.core.key);
4141
const keys = new KeyBuilderCS(prefix, matchingKey);
4242
const expirationTimestamp = Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS;
@@ -55,6 +55,12 @@ export function InLocalStorage(options: InLocalStorageOptions = {}): IStorageSyn
5555
telemetry: shouldRecordTelemetry(params) ? new TelemetryCacheInMemory(splits, segments) : undefined,
5656
uniqueKeys: impressionsMode === NONE ? new UniqueKeysCacheInMemoryCS() : undefined,
5757

58+
init() {
59+
if (settings.mode === LOCALHOST_MODE || splits.getChangeNumber() > -1) {
60+
Promise.resolve().then(onReadyFromCacheCb);
61+
}
62+
},
63+
5864
destroy() {
5965
this.splits = new SplitsCacheInMemory(__splitFiltersValidation);
6066
this.segments = new MySegmentsCacheInMemory();

src/storages/types.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,6 @@ export interface ISplitsCacheBase {
208208
// only for Client-Side. Returns true if the storage is not synchronized yet (getChangeNumber() === -1) or contains a FF using segments or large segments
209209
usesSegments(): MaybeThenable<boolean>,
210210
clear(): MaybeThenable<boolean | void>,
211-
// should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE.
212-
checkCache(): MaybeThenable<boolean>,
213211
killLocally(name: string, defaultTreatment: string, changeNumber: number): MaybeThenable<boolean>,
214212
getNamesByFlagSets(flagSets: string[]): MaybeThenable<ISet<string>[]>
215213
}
@@ -226,7 +224,6 @@ export interface ISplitsCacheSync extends ISplitsCacheBase {
226224
trafficTypeExists(trafficType: string): boolean,
227225
usesSegments(): boolean,
228226
clear(): void,
229-
checkCache(): boolean,
230227
killLocally(name: string, defaultTreatment: string, changeNumber: number): boolean,
231228
getNamesByFlagSets(flagSets: string[]): ISet<string>[]
232229
}
@@ -243,7 +240,6 @@ export interface ISplitsCacheAsync extends ISplitsCacheBase {
243240
trafficTypeExists(trafficType: string): Promise<boolean>,
244241
usesSegments(): Promise<boolean>,
245242
clear(): Promise<boolean | void>,
246-
checkCache(): Promise<boolean>,
247243
killLocally(name: string, defaultTreatment: string, changeNumber: number): Promise<boolean>,
248244
getNamesByFlagSets(flagSets: string[]): Promise<ISet<string>[]>
249245
}
@@ -498,6 +494,7 @@ export interface IStorageFactoryParams {
498494
* It is meant for emitting SDK_READY event in consumer mode, and waiting before using the storage in the synchronizer.
499495
*/
500496
onReadyCb: (error?: any) => void,
497+
onReadyFromCacheCb: (error?: any) => void,
501498
}
502499

503500
export type StorageType = 'MEMORY' | 'LOCALSTORAGE' | 'REDIS' | 'PLUGGABLE';

src/sync/offline/syncTasks/fromObjectSyncTask.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { syncTaskFactory } from '../../syncTask';
77
import { ISyncTask } from '../../types';
88
import { ISettings } from '../../../types';
99
import { CONTROL } from '../../../utils/constants';
10-
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
10+
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
1111
import { SYNC_OFFLINE_DATA, ERROR_SYNC_OFFLINE_LOADING } from '../../../logger/constants';
1212

1313
/**
@@ -60,12 +60,8 @@ export function fromObjectUpdaterFactory(
6060

6161
if (startingUp) {
6262
startingUp = false;
63-
Promise.resolve(splitsCache.checkCache()).then(cacheReady => {
64-
// Emits SDK_READY_FROM_CACHE
65-
if (cacheReady) readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
66-
// Emits SDK_READY
67-
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
68-
});
63+
// Emits SDK_READY
64+
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
6965
}
7066
return true;
7167
});

src/sync/polling/updaters/splitChangesUpdater.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ISplitChangesFetcher } from '../fetchers/types';
44
import { ISplit, ISplitChangesResponse, ISplitFiltersValidation } from '../../../dtos/types';
55
import { ISplitsEventEmitter } from '../../../readiness/types';
66
import { timeout } from '../../../utils/promise/timeout';
7-
import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
7+
import { SDK_SPLITS_ARRIVED } from '../../../readiness/constants';
88
import { ILogger } from '../../../logger/types';
99
import { SYNC_SPLITS_FETCH, SYNC_SPLITS_NEW, SYNC_SPLITS_REMOVED, SYNC_SPLITS_SEGMENTS, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
1010
import { startsWith } from '../../../utils/lang';
@@ -153,7 +153,8 @@ export function splitChangesUpdaterFactory(
153153
*/
154154
function _splitChangesUpdater(since: number, retry = 0): Promise<boolean> {
155155
log.debug(SYNC_SPLITS_FETCH, [since]);
156-
const fetcherPromise = Promise.resolve(splitUpdateNotification ?
156+
157+
return Promise.resolve(splitUpdateNotification ?
157158
{ splits: [splitUpdateNotification.payload], till: splitUpdateNotification.changeNumber } :
158159
splitChangesFetcher(since, noCache, till, _promiseDecorator)
159160
)
@@ -200,15 +201,6 @@ export function splitChangesUpdaterFactory(
200201
}
201202
return false;
202203
});
203-
204-
// After triggering the requests, if we have cached splits information let's notify that to emit SDK_READY_FROM_CACHE.
205-
// Wrapping in a promise since checkCache can be async.
206-
if (splitsEventEmitter && startingUp) {
207-
Promise.resolve(splits.checkCache()).then(isCacheReady => {
208-
if (isCacheReady) splitsEventEmitter.emit(SDK_SPLITS_CACHE_LOADED);
209-
});
210-
}
211-
return fetcherPromise;
212204
}
213205

214206
let sincePromise = Promise.resolve(splits.getChangeNumber()); // `getChangeNumber` never rejects or throws error

0 commit comments

Comments
 (0)