Skip to content

Commit 247213c

Browse files
committed
unify config store setting and round out bootstrap method
1 parent 3defee3 commit 247213c

File tree

6 files changed

+75
-41
lines changed

6 files changed

+75
-41
lines changed

src/client/eppo-client.ts

Lines changed: 60 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ import { TLRUInMemoryAssignmentCache } from '../cache/tlru-in-memory-assignment-
1717
import ConfigurationRequestor from '../configuration-requestor';
1818
import { ConfigurationManager } from '../configuration-store/configuration-manager';
1919
import { IConfigurationStore, ISyncStore } from '../configuration-store/configuration-store';
20-
import { IConfigurationManager } from '../configuration-store/i-configuration-manager';
20+
import {
21+
ConfigurationStoreBundle,
22+
IConfigurationManager,
23+
} from '../configuration-store/i-configuration-manager';
2124
import { MemoryOnlyConfigurationStore } from '../configuration-store/memory.store';
2225
import {
2326
ConfigurationWireV1,
@@ -43,7 +46,10 @@ import {
4346
IFlagEvaluationDetails,
4447
} from '../flag-evaluation-details-builder';
4548
import { FlagEvaluationError } from '../flag-evaluation-error';
46-
import FetchHttpClient from '../http-client';
49+
import FetchHttpClient, {
50+
IBanditParametersResponse,
51+
IUniversalFlagConfigResponse,
52+
} from '../http-client';
4753
import { IConfiguration } from '../i-configuration';
4854
import {
4955
BanditModelData,
@@ -173,9 +179,8 @@ export default class EppoClient {
173179
// Initialize the configuration manager
174180
this.configurationManager = new ConfigurationManager(
175181
this.flagConfigurationStore,
176-
this.banditVariationConfigurationStore ||
177-
new MemoryOnlyConfigurationStore<BanditVariation[]>(),
178-
this.banditModelConfigurationStore || new MemoryOnlyConfigurationStore<BanditParameters>(),
182+
this.banditVariationConfigurationStore,
183+
this.banditModelConfigurationStore,
179184
);
180185
}
181186

@@ -244,46 +249,54 @@ export default class EppoClient {
244249
this.configurationRequestParameters = configurationRequestParameters;
245250
}
246251

252+
public setConfigurationStores(configStores: ConfigurationStoreBundle) {
253+
// Update the configuration manager
254+
this.configurationManager.setConfigurationStores(configStores);
255+
}
256+
257+
// noinspection JSUnusedGlobalSymbols
258+
/**
259+
* @deprecated use `setConfigurationStores` instead
260+
*/
247261
setFlagConfigurationStore(flagConfigurationStore: IConfigurationStore<Flag | ObfuscatedFlag>) {
248262
this.flagConfigurationStore = flagConfigurationStore;
249263
this.configObfuscatedCache = undefined;
250264

251265
// Update the configuration manager
252-
this.configurationManager.setConfigurationStores({
253-
flagConfigurationStore: this.flagConfigurationStore,
254-
banditReferenceConfigurationStore:
255-
this.banditVariationConfigurationStore ||
256-
new MemoryOnlyConfigurationStore<BanditVariation[]>(),
257-
banditConfigurationStore:
258-
this.banditModelConfigurationStore || new MemoryOnlyConfigurationStore<BanditParameters>(),
259-
});
266+
this.innerSetConfigurationStores();
260267
}
261268

269+
// noinspection JSUnusedGlobalSymbols
270+
/**
271+
* @deprecated use `setConfigurationStores` instead
272+
*/
262273
setBanditVariationConfigurationStore(
263274
banditVariationConfigurationStore: IConfigurationStore<BanditVariation[]>,
264275
) {
265276
this.banditVariationConfigurationStore = banditVariationConfigurationStore;
266277

267278
// Update the configuration manager
268-
this.configurationManager.setConfigurationStores({
269-
flagConfigurationStore: this.flagConfigurationStore,
270-
banditReferenceConfigurationStore: this.banditVariationConfigurationStore,
271-
banditConfigurationStore:
272-
this.banditModelConfigurationStore || new MemoryOnlyConfigurationStore<BanditParameters>(),
273-
});
279+
this.innerSetConfigurationStores();
274280
}
275281

282+
// noinspection JSUnusedGlobalSymbols
283+
/**
284+
* @deprecated use `setConfigurationStores` instead
285+
*/
276286
setBanditModelConfigurationStore(
277287
banditModelConfigurationStore: IConfigurationStore<BanditParameters>,
278288
) {
279289
this.banditModelConfigurationStore = banditModelConfigurationStore;
280290

281291
// Update the configuration manager
282-
this.configurationManager.setConfigurationStores({
292+
this.innerSetConfigurationStores();
293+
}
294+
295+
private innerSetConfigurationStores() {
296+
// Set the set of configuration stores to those owned by the `this`.
297+
this.setConfigurationStores({
283298
flagConfigurationStore: this.flagConfigurationStore,
284-
banditReferenceConfigurationStore:
285-
this.banditVariationConfigurationStore ||
286-
new MemoryOnlyConfigurationStore<BanditVariation[]>(),
299+
banditReferenceConfigurationStore: this.banditVariationConfigurationStore,
287300
banditConfigurationStore: this.banditModelConfigurationStore,
288301
});
289302
}
@@ -326,32 +339,49 @@ export default class EppoClient {
326339
);
327340
}
328341

329-
bootstrap(configuration: IConfigurationWire) {
342+
/**
343+
* Initializes the `EppoClient` from the provided configuration. This method is async only to
344+
* accommodate writing to a persistent store. For fastest initialization, (at the cost of persisting configuration),
345+
* use `bootstrap` in conjunction with `MemoryOnlyConfigurationStore` instances which won't do an async write.
346+
*/
347+
async bootstrap(configuration: IConfigurationWire): Promise<void> {
330348
if (!configuration.config) {
331349
throw new Error('Flag configuration not provided');
332350
}
333-
const flagConfigResponse = inflateResponse(configuration.config.response);
334-
const banditParamResponse = configuration.bandits
351+
const flagConfigResponse: IUniversalFlagConfigResponse = inflateResponse(
352+
configuration.config.response,
353+
);
354+
const banditParamResponse: IBanditParametersResponse | undefined = configuration.bandits
335355
? inflateResponse(configuration.bandits.response)
336356
: undefined;
337357

338-
this.configurationManager.hydrateConfigurationStoresFromUfc(
358+
// We need to run this method sync, but, because the configuration stores potentially have an async write at the end
359+
// of updating the configuration, the method to do so it also async. Use an IIFE to wrap the async call.
360+
await this.configurationManager.hydrateConfigurationStoresFromUfc(
339361
flagConfigResponse,
340362
banditParamResponse,
341363
);
342364

343365
// Still initialize the client in case polling is needed.
344-
this.inititalize();
366+
// fire-and-forget so ignore the resolution of this promise.
367+
this.initialize()
368+
.then(() => {
369+
logger.debug('Eppo SDK polling initialization complete');
370+
return;
371+
})
372+
.catch((e) => {
373+
logger.error('Eppo SDK Error initializing polling after bootstrap()', e);
374+
});
345375
}
346376

347377
/**
348378
* @deprecated use `initialize` instead.
349379
*/
350380
async fetchFlagConfigurations() {
351-
return this.inititalize();
381+
return this.initialize();
352382
}
353383

354-
async inititalize() {
384+
async initialize() {
355385
if (!this.configurationRequestParameters) {
356386
throw new Error(
357387
'Eppo SDK unable to fetch flag configurations without configuration request parameters',

src/client/test-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export async function initConfiguration(
1919
const httpClient = new FetchHttpClient(apiEndpoints, 1000);
2020
const configurationRequestor = new ConfigurationRequestor(
2121
httpClient,
22-
new ConfigurationManager(configurationStore, null, null),
22+
new ConfigurationManager(configurationStore),
2323
false,
2424
);
2525
await configurationRequestor.fetchAndStoreConfigurations();

src/configuration-store/configuration-manager.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ describe('ConfigurationManager', () => {
3939
});
4040

4141
it('should handle null bandit stores', () => {
42-
const managerWithNullStores = new ConfigurationManager(flagStore, null, null);
42+
const managerWithNullStores = new ConfigurationManager(flagStore);
4343
const config = managerWithNullStores.getConfiguration();
4444
expect(config).toBeInstanceOf(StoreBackedConfiguration);
4545
expect(config.getFlagKeys()).toEqual([]);

src/configuration-store/configuration-manager.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ export class ConfigurationManager implements IConfigurationManager {
2020

2121
constructor(
2222
private flagConfigurationStore: IConfigurationStore<Flag | ObfuscatedFlag>,
23-
private banditReferenceConfigurationStore: IConfigurationStore<BanditVariation[]> | null,
24-
private banditConfigurationStore: IConfigurationStore<BanditParameters> | null,
23+
private banditReferenceConfigurationStore?: IConfigurationStore<BanditVariation[]>,
24+
private banditConfigurationStore?: IConfigurationStore<BanditParameters>,
2525
) {
2626
this.configuration = new StoreBackedConfiguration(
2727
this.flagConfigurationStore,
@@ -101,8 +101,8 @@ export class ConfigurationManager implements IConfigurationManager {
101101
banditConfigurationStore?: IConfigurationStore<BanditParameters>;
102102
}): void {
103103
this.flagConfigurationStore = configStores.flagConfigurationStore;
104-
this.banditReferenceConfigurationStore = configStores.banditReferenceConfigurationStore ?? null;
105-
this.banditConfigurationStore = configStores.banditConfigurationStore ?? null;
104+
this.banditReferenceConfigurationStore = configStores.banditReferenceConfigurationStore;
105+
this.banditConfigurationStore = configStores.banditConfigurationStore;
106106

107107
// Recreate the configuration with the new stores
108108
this.configuration = new StoreBackedConfiguration(

src/configuration-store/i-configuration-manager.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import { BanditParameters, BanditVariation, Flag, ObfuscatedFlag } from '../inte
44

55
import { IConfigurationStore } from './configuration-store';
66

7+
export type ConfigurationStoreBundle = {
8+
flagConfigurationStore: IConfigurationStore<Flag | ObfuscatedFlag>;
9+
banditReferenceConfigurationStore?: IConfigurationStore<BanditVariation[]>;
10+
banditConfigurationStore?: IConfigurationStore<BanditParameters>;
11+
};
12+
713
export interface IConfigurationManager {
814
getConfiguration(): IConfiguration;
915
hydrateConfigurationStores(
@@ -15,9 +21,5 @@ export interface IConfigurationManager {
1521
flags: IUniversalFlagConfigResponse,
1622
bandits?: IBanditParametersResponse,
1723
): Promise<boolean>;
18-
setConfigurationStores(configStores: {
19-
flagConfigurationStore: IConfigurationStore<Flag | ObfuscatedFlag>;
20-
banditReferenceConfigurationStore?: IConfigurationStore<BanditVariation[]>;
21-
banditConfigurationStore?: IConfigurationStore<BanditParameters>;
22-
}): void;
24+
setConfigurationStores(configStores: ConfigurationStoreBundle): void;
2325
}

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
ISyncStore,
3333
} from './configuration-store/configuration-store';
3434
import { HybridConfigurationStore } from './configuration-store/hybrid.store';
35+
import { ConfigurationStoreBundle } from './configuration-store/i-configuration-manager';
3536
import { MemoryStore, MemoryOnlyConfigurationStore } from './configuration-store/memory.store';
3637
import { ConfigurationWireHelper } from './configuration-wire/configuration-wire-helper';
3738
import {
@@ -110,6 +111,7 @@ export {
110111
MemoryStore,
111112
HybridConfigurationStore,
112113
MemoryOnlyConfigurationStore,
114+
ConfigurationStoreBundle,
113115

114116
// Assignment cache
115117
AssignmentCacheKey,

0 commit comments

Comments
 (0)