Loading feature flags from new endpoint#738
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds support for loading feature flags from Azure App Configuration’s newer feature-flag endpoint and introduces an option to exclude “classic” feature flags stored under the .appconfig.featureflag/ key namespace.
Changes:
- Add opt-in behavior to exclude classic feature flags and prefer the new feature-flag endpoint as the source of truth.
- Introduce “new feature-flag selector/watcher” markers and update selector equality/hash behavior accordingly.
- Implement loading + change detection for the new feature-flag endpoint, including synthesis into the existing feature-management JSON schema.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Models/KeyValueWatcher.cs | Adds a flag to distinguish watchers targeting the new feature-flag endpoint. |
| src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Models/KeyValueSelector.cs | Adds a flag to distinguish selectors for the new endpoint and updates equality/hash logic. |
| src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureFlagSettingConverter.cs | New converter that synthesizes ConfigurationSetting instances from SDK FeatureFlag models using the existing feature-management JSON schema. |
| src/Microsoft.Extensions.Configuration.AzureAppConfiguration/FeatureManagement/FeatureFlagOptions.cs | Adds a new public option to exclude classic feature flags. |
| src/Microsoft.Extensions.Configuration.AzureAppConfiguration/Extensions/ConfigurationClientExtensions.cs | Adds change detection for the new feature-flag endpoint by comparing page ETags. |
| src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationProvider.cs | Routes loading/refresh logic between classic key-values and the new feature-flag endpoint; ensures new flags win on key conflicts. |
| src/Microsoft.Extensions.Configuration.AzureAppConfiguration/AzureAppConfigurationOptions.cs | Updates UseFeatureFlags to register new-endpoint selectors/watchers (and optionally omit classic flags); changes default SDK service version. |
| // The new endpoint uses null to mean "any name". A bare "*" is equivalent. | ||
| if (string.IsNullOrEmpty(nameFilter) || nameFilter == "*") | ||
| { | ||
| nameFilter = null; | ||
| } |
| private static ConfigurationClientOptions GetDefaultClientOptions() | ||
| { | ||
| var clientOptions = new ConfigurationClientOptions(ConfigurationClientOptions.ServiceVersion.V2023_11_01); | ||
| var clientOptions = new ConfigurationClientOptions(ConfigurationClientOptions.ServiceVersion.V2026_05_01_Preview); | ||
| clientOptions.Retry.MaxRetries = MaxRetries; |
| /// <summary> | ||
| /// When set to true, classic feature flags (key-values whose key is prefixed with | ||
| /// ".appconfig.featureflag/") are not loaded from the configuration store. Only feature flags | ||
| /// returned by the new feature-flag endpoint will be loaded. | ||
| /// Defaults to false; classic flags are loaded alongside new flags for backward compatibility. | ||
| /// </summary> | ||
| public bool ExcludeClassicFeatureFlags { get; set; } = false; |
| IsNewFeatureFlagSelector = true | ||
| }; | ||
|
|
||
| _selectors.AppendUnique(newFfSelector); |
There was a problem hiding this comment.
I think we should separate key value selectors and feature flag selectors.
And I don't believe we need to duplicate the feature flag selectors and watchers.
Whenever we are processing feature flag selectors we know we must
- take the name filter, append the classic feature flag prefix, query classic feature flags
- Take the name filter, use it to query standalone (new) feature flags.
|
|
||
| foreach (SdkFeatureFlag ff in page.Values) | ||
| { | ||
| ConfigurationSetting synthesized = FeatureFlagSettingConverter.ToConfigurationSetting(ff); |
There was a problem hiding this comment.
The new feature flags shouldn't be converted to configuration setting. When we load a new feature flag, we should break it down into it's associated key-value pairs, like the feature flag adapter does for classic feature flags, and inject that into the configuration directly.
There was a problem hiding this comment.
I saw some updates in the PR. Is this one still being worked on?
There was a problem hiding this comment.
Yes, working in progess
|
This needs to go into the preview branch. |
708b5b1 to
56f906e
Compare
| { | ||
| var selector = new SettingSelector() | ||
| { | ||
| KeyFilter = FeatureManagementConstants.FeatureFlagMarker + (ffSelector.NameFilter ?? "*"), |
There was a problem hiding this comment.
This fall back to "*" is interesting. How would we end up with a feature flag selector with a null name filter. would that be
ffOptions.Select(null);
I would've thought that we would throw if someone passes null for the name filter.
Previously, feature flags were loaded only as classic key-values prefixed with
.appconfig.featureflag/. This PR registers a parallel "new feature flag" selector/watcher for each FeatureFlagSelector, fetches flags via the dedicated SDK endpoint, and synthesizes them back into the feature-management JSON schema so downstream parsing is unchanged. Classic flags can be turned off via a new opt-in flagExcludeClassicFeatureFlags.Changes: