Skip to content

Commit 60c8617

Browse files
committed
refactor: don't fetch bandits if current model is up-to-date
[ci skip]
1 parent d4c6f06 commit 60c8617

File tree

1 file changed

+42
-13
lines changed

1 file changed

+42
-13
lines changed

src/configuration-requestor.ts

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { Configuration } from './configuration';
1+
import { BanditsConfig, Configuration, FlagsConfig } from './configuration';
22
import { ConfigurationStore } from './configuration-store';
33
import { IHttpClient } from './http-client';
44

55
export type ConfigurationRequestorOptions = {
6-
wantsBandits?: boolean;
6+
wantsBandits: boolean;
77
};
88

99
// Requests AND stores flag configurations
@@ -22,21 +22,14 @@ export default class ConfigurationRequestor {
2222
}
2323

2424
async fetchConfiguration(): Promise<Configuration | null> {
25-
const configResponse = await this.httpClient.getUniversalFlagConfiguration();
26-
if (!configResponse?.response.flags) {
25+
const flags = await this.httpClient.getUniversalFlagConfiguration();
26+
if (!flags?.response.flags) {
2727
return null;
2828
}
2929

30-
const needsBandits =
31-
this.options.wantsBandits &&
32-
Object.keys(configResponse.response.banditReferences ?? {}).length > 0;
33-
34-
const banditsConfig = needsBandits ? await this.httpClient.getBanditParameters() : undefined;
30+
const bandits = await this.getBanditsFor(flags);
3531

36-
return Configuration.fromResponses({
37-
flags: configResponse,
38-
bandits: banditsConfig,
39-
});
32+
return Configuration.fromResponses({ flags, bandits });
4033
}
4134

4235
async fetchAndStoreConfigurations(): Promise<void> {
@@ -45,4 +38,40 @@ export default class ConfigurationRequestor {
4538
this.configurationStore.setConfiguration(configuration);
4639
}
4740
}
41+
42+
/**
43+
* Get bandits configuration matching the flags configuration.
44+
*
45+
* This function does not fetch bandits if the client does not want
46+
* them (`ConfigurationRequestorOptions.wantsBandits === false`) or
47+
* we we can reuse bandit models from `ConfigurationStore`.
48+
*/
49+
private async getBanditsFor(flags: FlagsConfig): Promise<BanditsConfig | undefined> {
50+
const needsBandits =
51+
this.options.wantsBandits && Object.keys(flags.response.banditReferences ?? {}).length > 0;
52+
if (!needsBandits) {
53+
return undefined;
54+
}
55+
56+
const prevBandits = this.configurationStore.getConfiguration().getBanditConfiguration();
57+
const canReuseBandits = banditsUpToDate(flags, prevBandits);
58+
if (canReuseBandits) {
59+
return prevBandits;
60+
}
61+
62+
return await this.httpClient.getBanditParameters();
63+
}
4864
}
65+
66+
/**
67+
* Checks that bandits configuration matches the flags
68+
* configuration. This is done by checking that bandits configuration
69+
* has proper versions for all bandits references in flags
70+
* configuration.
71+
*/
72+
const banditsUpToDate = (flags: FlagsConfig, bandits: BanditsConfig | undefined): boolean => {
73+
const banditParams = bandits?.response.bandits ?? {};
74+
return Object.entries(flags.response.banditReferences ?? {}).every(
75+
([banditKey, reference]) => reference.modelVersion === banditParams[banditKey]?.modelVersion,
76+
);
77+
};

0 commit comments

Comments
 (0)