Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RegisterAll API to enable monitoring collections of key-values for refresh #574

Merged
merged 81 commits into from
Jan 22, 2025

Conversation

amerjusupovic
Copy link
Member

@amerjusupovic amerjusupovic commented Jul 15, 2024

This PR adds the new RegisterAll API to monitor any key-values added with AzureAppConfigurationOptions.Select for refresh as a collection, but it will also begin monitoring feature flags as a collection instead of on an individual basis. Consequently, feature flag changes will no longer be logged on an individual basis. This solves an existing issue.

/// <summary>
/// For use in tests only. An optional class used to process pageable results from Azure App Configuration.
/// </summary>
internal IPageableConfigurationSettings PageableConfigurationSettings { get; set; }
Copy link
Member

@jimmyca15 jimmyca15 Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggested this name (IPageableConfigurationSettings), and I think it was a bad suggestion. Because this is not configuration settings, it is indeed something that iterates through pages. The original name IConfigurationSettingsPageIterator would be better, or something along those lines.

bool hasWatchers = watchers.Any();
TimeSpan minWatcherRefreshInterval = hasWatchers ? watchers.Min(w => w.RefreshInterval) : TimeSpan.MaxValue;

if (options.RegisterAllEnabled)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The embedded ternary condition in the else statement makes more sense to be a part of the upper if/else.

if (registerAllEnabled)
{
    
}
else if (watchers.Any())
{

}
else
{
    
}


foreach (KeyValueWatcher changeWatcher in refreshableWatchers.Concat(refreshableMultiKeyWatchers))
// Invalidate all the cached KeyVault secrets
foreach (IKeyValueAdapter adapter in _options.Adapters)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do deleted flags get removed?

Copy link
Member Author

@amerjusupovic amerjusupovic Jan 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discussed offline, lost this along the way when restructuring the refresh methods. I'll try checking the existing data and using that to decide whether the setting for that flag's key should be updated. Might need a new data structure/method for this

@@ -22,12 +22,14 @@ internal class LoggingConstants
public const string RefreshKeyVaultSecretRead = "Secret read from Key Vault for key-value.";
public const string RefreshFeatureFlagRead = "Feature flag read from App Configuration.";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, will remove

ffKeys,
cancellationToken).ConfigureAwait(false);

logInfoBuilder.Append(LogHelper.BuildFeatureFlagsUpdatedMessage());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see anywhere that we logged feature flag updates as info before. Am I missing it.

Also, why

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had a LogFeatureFlagUpdated message when refreshing individual flags in the ConfigurationClientExtensions file, so I thought it might make sense to log the collection being updated since it seems like whenever we update a value (kv, flag, secret) we would log it as info.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. In that case, I see for configuration we log "Configuration reloaded.", but for flags it is currently "Feature flags updated." It seems to me we should be consistent and log "Feature flags reloaded."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, they both do a full reload so it makes sense

Comment on lines 1311 to 1314
if (haveCollectionsChanged)
{
return haveCollectionsChanged;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (haveCollectionsChanged)
{
return haveCollectionsChanged;
}
if (haveCollectionsChanged)
{
return true;
}

@@ -376,18 +406,40 @@ public AzureAppConfigurationOptions ConfigureClientOptions(Action<ConfigurationC
/// <param name="configure">A callback used to configure Azure App Configuration refresh options.</param>
public AzureAppConfigurationOptions ConfigureRefresh(Action<AzureAppConfigurationRefreshOptions> configure)
{
if (RegisterAllEnabled)
{
throw new ArgumentException($"{nameof(ConfigureRefresh)}() cannot be invoked multiple times when {nameof(AzureAppConfigurationRefreshOptions.RegisterAll)} has been invoked.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be an invalid operation exception. There aren't any invalid arguments.


if (!isRegisterCalled && !RegisterAllEnabled)
{
throw new ArgumentException($"{nameof(ConfigureRefresh)}() must register at least one key-value for refresh or enable refresh of all selected key-values.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that one must either call Register or RegisterAll, if so then I think it would be helpful to mention that explicitly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, since we required calling Register before, so now at least one should be called. I can update it to mention the specific APIs instead of this description in the exception

{
throw new ArgumentException($"{nameof(ConfigureRefresh)}() must have at least one key-value registered for refresh.");
throw new ArgumentException($"Cannot call both {nameof(AzureAppConfigurationRefreshOptions.RegisterAll)} and "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InvalidOperationException.


if (!isRegisterCalled && !RegisterAllEnabled)
{
throw new ArgumentException($"{nameof(ConfigureRefresh)}() must call either {nameof(AzureAppConfigurationRefreshOptions.Register)}()" +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also be an invalid operation exception since there are no invalid arguments.

@@ -10,5 +10,6 @@ internal class ErrorMessages
public const string FeatureFlagInvalidJsonProperty = "Invalid property '{0}' for feature flag. Key: '{1}'. Found type: '{2}'. Expected type: '{3}'.";
public const string FeatureFlagInvalidFormat = "Invalid json format for feature flag. Key: '{0}'.";
public const string InvalidKeyVaultReference = "Invalid Key Vault reference.";
public const string InvalidConfigurationSettingPage = "Invalid page while loading configuration settings.";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not used. File changes can be reverted.

@amerjusupovic amerjusupovic merged commit 5e6a012 into preview Jan 22, 2025
3 checks passed
@amerjusupovic amerjusupovic deleted the ajusupovic/collection-monitoring branch January 22, 2025 20:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants