Following Resiliency and disaster recovery recommendations we should configure two Azure AppConfiguration stores. I'm trying to apply the same approach to Azure Functions. But as it is shown in this example IConfigurationRefresher configured for one store. What would be the right way to provide dynamic configuration in this case? Configure separate refreshers for both of stores?
Is there a way of using IOptionsMonitor to control changes?
@sslepova Yes, you could configure refresh for both the stores. I have shared a sample code snippet below.
The IConfigurationRefresher instances can be used to trigger on-demand refresh. This operation is not supported through IOptionsMonitor. In order to make the refresher instances available through dependency injection, you could inject the IConfiguration instance to the service collection, and then call the AddAzureAppConfiguration(IServiceCollection) method. This will make an instance of IConfigurationRefresherProvider available through dependency injection, and its Refreshers property will provide the refresher instances for each configured store.
```` csharp
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureAppConfiguration((hostingContext, config) =>
{
var settings = config.Build();
Action<AzureAppConfigurationOptions> optionsInitializer = (options) =>
{
options.Select("Settings:*")
.ConfigureRefresh(refresh =>
{
refresh.Register("Settings:BackgroundColor");
});
};
config.AddAzureAppConfiguration(options =>
{
options.Connect(settings["ConnectionString_SecondaryStore"]);
optionsInitializer.Invoke(options);
}, optional: true)
.AddAzureAppConfiguration(options =>
{
options.Connect(settings["ConnectionString_PrimaryStore"]);
optionsInitializer.Invoke(options);
}, optional: true);
});
webBuilder.UseStartup<Startup>();
});
}
````
API Reference
AddAzureAppConfiguration(IServiceCollection)
IConfigurationRefresherProvider.Refreshers
Thanks for the response, @abhilasharora. Just to clarify: I'm talking about Azure Functions, so by default, app doesn't create host builder explicitly. According to this one should add a startup class inherited from FunctionsStartup, where ConfigurationBuilder.AddAzureAppConfiguration and IConfigurationRefresher are involved. Refresher then configured as singleton service.
So, if I combine these two approaches (to configure two stores and get a refresher from options) don't I end up with two refreshers?) Or should I firstly create AzureAppConfigurationOptions instance, use it to configure both AppConfiguration stores, and get a refresher? If that's possible could you please share an example.
@sslepova I had a chance to discuss your scenario with the team. In case the primary AppConfiguration instance goes down, the goal of disaster recovery handling is to ensure the following.
During the period when the primary App Configuration is down, there won't be any changes to the configuration in either the primary or the secondary App Configuration instance. For the above scenarios, it should be enough to configure refresh only for the primary App Configuration instance. Here is an example of how the code might look like for an Azure Function.
```` csharp
class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
IConfigurationRefresher configurationRefresher = null;
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddAzureAppConfiguration(options =>
{
options.Connect(Environment.GetEnvironmentVariable("ConnectionString_SecondaryStore"));
}, optional: true);
configurationBuilder.AddAzureAppConfiguration(options =>
{
options.Connect(Environment.GetEnvironmentVariable("ConnectionString_PrimaryStore"))
.Select("TestApp:*")
.ConfigureRefresh(refreshOptions => refreshOptions.Register("TestApp:Settings:Sentinel", refreshAll: true))
.UseFeatureFlags();
configurationRefresher = options.GetRefresher();
}, optional: true);
IConfiguration configuration = configurationBuilder.Build();
builder.Services.Configure<Settings>(configuration.GetSection("TestApp:Settings"));
builder.Services.AddFeatureManagement(configuration);
builder.Services.AddSingleton<IConfigurationRefresher>(configurationRefresher);
}
}
````
@abhilasharora I think what you said in the last response can be useful guidance to other customers as well. Do you mind to update our BCDR doc?