1- import { Configuration } from './configuration' ;
1+ import { BanditsConfig , Configuration , FlagsConfig } from './configuration' ;
22import { ConfigurationStore } from './configuration-store' ;
33import { IHttpClient } from './http-client' ;
44
55export 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