Refresh Azure app configuration in Azure functions and Console applications

In the last article here, we saw how we can use the built-in middleware to refresh the configurations and how our configuration is refreshed automatically. That article is applicable to the web applications, but what about the console applications or Azure functions apps ? For them, we need to adopt a different approach called activity based refresh, where azure configuration is tried to refresh based on demand or based on the activity. How can we do this, let’s check step by step.

For this article, we will try to use the Azure functions app for our demo and let’s see how we can refresh the configuration on demand. To check how we can set up the azure configuration explorer, you can follow my article here.

Before moving to the actual code, let’s try to add some configuration keys in the azure app configuration. In this we need to add two keys, one being the sentinel key and another being the key which we want to refresh automatically for that lets add two keys like below.

Let’s name first key as refresh and second key as Settings:Test

We have set up our app configuration till now it’s time to add some code and check how can we refresh the configuration dynamically, so let’s get started with the code.

To get started, we first need to add get the connection string of the Azure app configuration that we have created, we can copy the same from here.

Once we have the connection string, we can add it in the user secrets like below

dotnet user-secrets init

dotnet user-secrets set "ConnectionStrings:AzureAppConfigurationEndPoint" "<Your app configuration connection string goes here>"

Apart from user secrets, We can use the environment variable to read the connection string as well. It is not necessary to use the user secrets every time, they are only meant to secure your app settings in the development environment.

Once we have everything ready, let’s add some code and see how we can refresh the configuration. In this, we will add the following changes.

  1. Basic setup changes and Configuration setup
  2. Timer Function to refresh the app configuration
  3. Timer function to check the reloaded configuration

First change that we need to do is at the Program.cs like below

 Azureusing Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration;
using Microsoft.Extensions.DependencyInjection;
using RefreshConfiguration;
using System;

[assembly: WebJobsStartup(typeof(Program))]
namespace RefreshConfiguration
{

    public class Program : FunctionsStartup
    {
        public static IConfigurationRefresher _configRefresher;

        public override void Configure(IFunctionsHostBuilder builder)
        {

            builder.Services.AddAzureAppConfiguration();

            builder.Services.AddSingleton(_configRefresher);

            builder.Services.AddOptions<Settings>().Configure<IConfiguration>((settings, configuration) =>
            {
                configuration.GetSection(Settings.Name).Bind(settings);
            });
        }

        public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
        {

            builder.ConfigurationBuilder.AddUserSecrets<Program>();

            var configuration = builder.ConfigurationBuilder.Build();


            builder.ConfigurationBuilder.AddAzureAppConfiguration(opt =>
             {
                 var connectionString = configuration.GetConnectionString("AzureAppConfigurationEndPoint");
                 opt.Connect(connectionString).ConfigureRefresh(options =>
                {
                    options.Register("refresh", refreshAll: true)
                        .SetCacheExpiration(TimeSpan.FromSeconds(15));
                });

                 _configRefresher = opt.GetRefresher();
             });

        }

    }

}

Here in above class we are configuring the app configuration, and then we will add configure the needed dependencies for the application.

When you see the method ConfigureAppConfiguration It does

  1. We read the connection string for the Azure app configuration
  2. It adds the Azure app configuration and register the sentinel key and cache expiration duration
  3. It also sets the value for the configuration refresher.

This method we set the cache expiration duration this make sure minimum time before our configuration is refreshed. So in this case of on demand config refresher if the request is made before this duration configuration wont change and they will change only after the elapsed time of this caching. We have set this cache expiration duration to 15 seconds in order to test this flow

Next method in this class is Configure, In this method we register all the dependencies. The thing to remember here is to add the refresher as a dependency. Which we are going to use in the latter to try to refresh the configuration.

Before creating a function app using Visual Studio, we don’t get the initial setup code from templates, but we need to add that manually. For that, we can use the FunctionsStartup that will make sure we get all the boilerplate code that we want to get started.

Once we are done with the setting up the configuration, lets add some services in dependency like below

 public static IConfigurationRefresher _configRefresher;

        public override void Configure(IFunctionsHostBuilder builder)
        {

            builder.Services.AddAzureAppConfiguration();

            builder.Services.AddSingleton(_configRefresher);

            builder.Services.AddOptions<Settings>().Configure<IConfiguration>((settings, configuration) =>
            {
                configuration.GetSection(Settings.Name).Bind(settings);
            });
        }

Here is the method which will add the config refresher in the dependency which we will use in the code in the actual functions along with that we register all the azure app configuration dependencies in the store. Along with all these dependencies we will use Options pattern to add the Settings object in the configuration.

Once we are done with all settings and setup, let’s check our function, let’s design one function to refresh the configuration and another to check this refreshed configuration so lets check what we have in the first function

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration;
using Microsoft.Extensions.Logging;
using System;
using System.Threading.Tasks;

namespace RefreshConfiguration
{
    public class ReloadConfiguration
    {
        private readonly Settings _settings;
        private readonly IConfiguration _config;
        private readonly IConfigurationRefresher _refresher;
        public ReloadConfiguration( IConfigurationRefresher refresher)
        {
            _refresher = refresher ?? throw new ArgumentNullException(nameof(refresher));
        }

        [FunctionName("ReloadConfiguration")]
        public async Task Run([TimerTrigger("30 * * * * *")]TimerInfo myTimer, ILogger log)
        {
         
             _refresher.TryRefreshAsync();
            
            log.LogInformation("Configuration Refreshed");
        }
    }
}

When we look at the above function, it’s just a simple timer trigger function which will be triggered every 30 seconds and try to refresh the configuration store by connecting to the azure app configuration.

In this function we have not awaited the TryRefreshasync function intentionally so that it should not block other function from executing.

The second function we have is the Configuration demo which is another timer trigger function which will just display the values from the configuration store

the code block for that function is like below

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;

namespace RefreshConfiguration
{
    public  class ConfigurationDemo
    {
        private readonly Settings _settings;

        public ConfigurationDemo(IOptionsSnapshot<Settings> settings)
        {
            _settings = settings.Value;
        }

        [FunctionName("ConfigurationDemo")]
        public async Task Run([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer, ILogger log)
        {
           log.LogWarning($"Executing function and values refreshed are {_settings.Test}");
            
        }
    }
}

Above function is triggered every 1 minute and it just reloads the value of the settings object that we have added in the options . Once we are done with above code, lets see the actual output how it will look

Steps to refresh the configuration

  1. Update key you want to refresh in the application
  2. Change the Sentinel key so as the force refresh the configuration
  3. Wait for the cache expiration time to pass and refresher to execute once we have that we will have our configuration refreshed in the application

You can find code repo for this article here

Refrences

Tutorial: Use App Configuration dynamic configuration in ASP.NET Core – Azure App Configuration | Microsoft Docs

Tutorial for using Azure App Configuration dynamic configuration in an Azure Functions app | Microsoft Docs

Code Repository

dotnetgik/RefreshConfiguration at master (github.com)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s