load feature flags from new endpoint - #341
Conversation
There was a problem hiding this comment.
FeatureFlagConditions, FeatureFilter, .... all of these types/interfaces/enum are exported by the Azure SDK. We should use them instead of abusing any type.
There was a problem hiding this comment.
FeatureFlag related types exported in SDK are different with those defined by MS schema, that's why we need the converter. If imported them from SDK we still need to define the corresponding structs with snake_case field names. What concerns do you have about using the any type?
/** The conditions that must be met for the feature flag to be enabled. */
export interface FeatureFlagConditions {
/** The requirement type for the conditions. */
requirementType?: RequirementType;
/** The filters that will conditionally enable or disable the flag. */
filters?: FeatureFilter[];
}
/** A filter that conditionally enables or disables a feature flag. */
export interface FeatureFilter {
/** The name of the filter. */
name: string;
/** The parameters used by the filter. */
parameters?: { [propertyName: string]: string };
}| // Deep clone so the caller's option objects are never mutated. | ||
| const clonedSelectors = structuredClone(selectors); | ||
| clonedSelectors.forEach(selector => { | ||
| if (selector.keyFilter) { | ||
| selector.keyFilter = `${featureFlagPrefix}${selector.keyFilter}`; | ||
| } | ||
| }); | ||
| return getValidSettingSelectors(selectors); | ||
| return getValidSettingSelectors(clonedSelectors); |
There was a problem hiding this comment.
| // Deep clone so the caller's option objects are never mutated. | |
| const clonedSelectors = structuredClone(selectors); | |
| clonedSelectors.forEach(selector => { | |
| if (selector.keyFilter) { | |
| selector.keyFilter = `${featureFlagPrefix}${selector.keyFilter}`; | |
| } | |
| }); | |
| return getValidSettingSelectors(selectors); | |
| return getValidSettingSelectors(clonedSelectors); | |
| // Create prefixed copies because the original selectors are also used as unprefixed selectors for enhanced feature flags. | |
| const prefixedSelectors = selectors.map(selector => ({ | |
| ...selector, | |
| keyFilter: selector.keyFilter | |
| ? `${featureFlagPrefix}${selector.keyFilter}` | |
| : selector.keyFilter | |
| })); | |
| return getValidSettingSelectors(prefixedSelectors); |
| const lastServerResponseTime = pageWatchers[i].lastServerResponseTime; | ||
| let isResponseFresh = false; | ||
| if (lastServerResponseTime !== undefined) { | ||
| isResponseFresh = serverResponseTime > lastServerResponseTime; |
There was a problem hiding this comment.
In .NET, we use ">=". But I guess this behavior difference has existed before this PR. Let's align with .NET even though this difference will not affect anything in reality
| } | ||
| i++; | ||
| } | ||
| } |
There was a problem hiding this comment.
In .NET provider, we have an additional check to see whether there is more old pages.
To align with .NET, we should add
if (i < pageWatchers.length) {
return true;
}after the for loop here.
But this behavior difference has existed before this PR and it will not affect anything in reality, because we will have an empty page after a full page. That empty page will have different etag.
But add this additional check can make code more robust.
Summary
Adds support for loading feature flags from new endpoint (via
FeatureFlagClient.listFeatureFlags), in addition to the classic key-value path. When feature flags are enabled, the provider now loads flags from both sources and merges them, with flags from the new endpoint taking precedence over classic ones of the same name. Reference Azure/AppConfiguration-DotnetProvider#738Key changes
Added
appConfigClient.ts: anIAppConfigurationClientinterface plusAppConfigClientimplementation that wraps bothAppConfigurationClient(classic KV) andFeatureFlagClient(new FF endpoint). Each method applies request tracing before delegating to the underlying SDK client.Added
featureFlagConverter.tswithconvertToMicrosoftSchema(), which maps the SDK's typedFeatureFlag(camelCase) into the Microsoft Feature Management schema consumed byfeature_management.feature_flags.Load and merge on init and on refresh:
#loadClassicFeatureFlags()+#loadFeatureFlags() →#setFeatureFlags()dedups by name (new endpoint supersedes classic).Change detection covers both paths