Redesigning Configuration Refresh for Azure App Configuration

Abhilash Arora

Overview

Since its inception, the .NET Core configuration provider for Azure App Configuration has provided the capability to monitor changes and sync them to the configuration within a running application. We recently redesigned this functionality to allow for on-demand refresh of the configuration. The new design paves the way for smarter applications that only refresh the configuration when necessary. As a result, inactive applications no longer have to monitor for configuration changes unnecessarily.
 

Initial design : Timer-based watch

In the initial design, configuration was kept in sync with Azure App Configuration using a watch mechanism which ran on a timer. At the time of initialization of the Azure App Configuration provider, users could specify the configuration settings to be updated and an optional polling interval. In case the polling interval was not specified, a default value of 30 seconds was used.

public static IWebHost BuildWebHost(string[] args)
{
    WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            // Load settings from Azure App Configuration
            // Set up the provider to listen for changes triggered by a sentinel value
            var settings = config.Build();
            string appConfigurationEndpoint = settings["AzureAppConfigurationEndpoint"];

            config.AddAzureAppConfiguration(options =>
            {
                options.ConnectWithManagedIdentity(appConfigurationEndpoint)
                        .Use(keyFilter: "WebDemo:*")
                        .WatchAndReloadAll(key: "WebDemo:Sentinel", label: LabelFilter.Null);
            });

            settings = config.Build();
        })
        .UseStartup<Startup>()
        .Build();
}

For example, in the above code snippet, Azure App Configuration would be pinged every 30 seconds for changes. These calls would be made irrespective of whether the application was active or not. As a result, there would be unnecessary usage of network and CPU resources within inactive applications. Applications needed a way to trigger a refresh of the configuration on demand in order to be able to limit the refreshes to active applications. Then unnecessary checks for changes could be avoided.

This timer-based watch mechanism had the following fundamental design flaws.

  1. It could not be invoked on-demand.
  2. It continued to run in the background even in applications that could be considered inactive.
  3. It promoted constant polling of configuration rather than a more intelligent approach of updating configuration when applications are active or need to ensure freshness.
     

New design : Activity-based refresh

The new refresh mechanism allows users to keep their configuration updated using a middleware to determine activity. As long as the ASP.NET Core web application continues to receive requests, the configuration settings continue to get updated with the configuration store.

The application can be configured to trigger refresh for each request by adding the Azure App Configuration middleware from package Microsoft.Azure.AppConfiguration.AspNetCore in your application’s startup code.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseAzureAppConfiguration();
    app.UseMvc();
}

At the time of initialization of the configuration provider, the user can use the ConfigureRefresh method to register the configuration settings to be updated with an optional cache expiration time. In case the cache expiration time is not specified, a default value of 30 seconds is used.

public static IWebHost BuildWebHost(string[] args)
{
    WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((hostingContext, config) =>
        {
            // Load settings from Azure App Configuration
            // Set up the provider to listen for changes triggered by a sentinel value
            var settings = config.Build();
            string appConfigurationEndpoint = settings["AzureAppConfigurationEndpoint"];

            config.AddAzureAppConfiguration(options =>
            {
                options.ConnectWithManagedIdentity(appConfigurationEndpoint)
                        .Use(keyFilter: "WebDemo:*")
                        .ConfigureRefresh((refreshOptions) =>
                        {
                            // Indicates that all settings should be refreshed when the given key has changed
                            refreshOptions.Register(key: "WebDemo:Sentinel", label: LabelFilter.Null, refreshAll: true);
                        });
            });

            settings = config.Build();
        })
        .UseStartup<Startup>()
        .Build();
}

In order to keep the settings updated and avoid unnecessary calls to the configuration store, an internal cache is used for each setting. Until the cached value of a setting has expired, the refresh operation does not update the value. This happens even when the value has changed in the configuration store.  

Try it now!

For more information about Azure App Configuration, check out the following resources. You can find step-by-step tutorials that would help you get started with dynamic configuration using the new refresh mechanism within minutes. Please let us know what you think by filing issues on GitHub.

Overview: Azure App configuration
Tutorial: Use dynamic configuration in an ASP.NET Core app
Tutorial: Use dynamic configuration in a .NET Core app
Related Blog: Configuring a Server-side Blazor app with Azure App Configuration

2 comments

Discussion is closed. Login to edit/delete existing comments.

  • John King 0

    Won’t the new design bad for  IHostedService , why not use TCP or WebSocket to do the change detect?

    • Abhilash AroraMicrosoft employee 0

      Since hosted services in ASP.NET Core applications do not handle requests, these won’t be able to benefit from the auto-refresh mechanism provided by the middleware. For such scenarios, we expose an interface that allows users to invoke refresh manually as needed. Details on the interface can be found here. Azure App Configuration is designed for slow-changing data systems, rather than being a real-time service. This provides the opportunity to offer lower prices to the customers. In contrast, TCP and web sockets are better suited for fast-evolution scenarios, and have higher associated costs. The holistic approach for Azure App Configuration is to reach customers across scenarios, platforms, frameworks and devices. We currently support two notification models – simple direct poll and push via Azure Event Grid. We are looking to extend our logistics to automatically integrate with applications natively running on or using Azure services (ARM, AppService, AKS, KeyVault, ServiceBus, VM etc.). We also plan to enable hyper-scaling configuration distribution, and cover external or on-premise server scenarios. As always, we desperately want to hear from any customers that don’t see Azure App Configuration fit as competitive solution for their configuration requirements. Feedback is critical and greatly appreciated.

Feedback usabilla icon