1
- import { Configuration } from './configuration' ;
1
+ import { BanditsConfig , Configuration , FlagsConfig } from './configuration' ;
2
2
import { ConfigurationStore } from './configuration-store' ;
3
3
import { IHttpClient } from './http-client' ;
4
4
5
5
export type ConfigurationRequestorOptions = {
6
- wantsBandits ? : boolean ;
6
+ wantsBandits : boolean ;
7
7
} ;
8
8
9
9
// Requests AND stores flag configurations
@@ -22,21 +22,14 @@ export default class ConfigurationRequestor {
22
22
}
23
23
24
24
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 ) {
27
27
return null ;
28
28
}
29
29
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 ) ;
35
31
36
- return Configuration . fromResponses ( {
37
- flags : configResponse ,
38
- bandits : banditsConfig ,
39
- } ) ;
32
+ return Configuration . fromResponses ( { flags, bandits } ) ;
40
33
}
41
34
42
35
async fetchAndStoreConfigurations ( ) : Promise < void > {
@@ -45,4 +38,40 @@ export default class ConfigurationRequestor {
45
38
this . configurationStore . setConfiguration ( configuration ) ;
46
39
}
47
40
}
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
+ }
48
64
}
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