Динамическое обновление конфигурации ASP.NET по запросу с помощью Azure App Configuration.
Что я пытаюсь сделать: я пытаюсь настроить обновление конфигурации ASP.Net по требованию, используя конфигурацию приложений Azure в качестве источника и подписку EventGrid на событие изменения ключа-значения с конечной точкой WebHook.
В чем моя проблема: когда событие достигает конечной точки, код выполняется без ошибок, но конфигурация в конце концов не обновляется.
Справочная информация и то, что я пробовал: я также пытался использовать метод опроса с дозорным ключом, который работает хорошо, но не кажется оптимальным решением, учитывая ограничение квоты конфигурации приложений Azure или необходимость ждать, когда истечет срок кэширования. .
Мой код: здесь я использую минимальный синтаксис API
using System.Text.Json;
using AppConfigurationSpike;
using Azure.Identity;
using Azure.Messaging.EventGrid;
using Azure.Messaging.EventGrid.SystemEvents;
using Microsoft.Extensions.Configuration.AzureAppConfiguration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration.Extensions;
using Microsoft.Extensions.Options;
var builder = WebApplication
.CreateBuilder(args);
// Load configuration from Azure App Configuration
builder.Host.ConfigureAppConfiguration((context, config) =>
{
var settings = config.Build();
config.AddAzureAppConfiguration(options =>
{
options.Connect(new Uri(settings["MyApp:AppConfigurationEndpoint"]), new DefaultAzureCredential())
// Load all keys that start with `MyApp:` and have no label
.Select("MyApp:*")
// Configure to reload configuration if the registered sentinel key is modified
.ConfigureRefresh(refreshOptions =>
refreshOptions.Register("MyApp:Settings:Sentinel", refreshAll: true)
.SetCacheExpiration(TimeSpan.FromDays(30)));
});
});
// Add Azure App Configuration middleware to the container of services.
builder.Services.AddAzureAppConfiguration();
builder.Services.Configure<Settings>(builder.Configuration.GetSection("MyApp:Settings"));
var app = builder.Build();
// Use Azure App Configuration middleware for dynamic configuration refresh.
app.UseAzureAppConfiguration();
// I use this endpoint for checking whether the configuration is updated or not.
app.MapGet("/", (IOptionsSnapshot<Settings> settings) => settings.Value.Key);
// A webhook for immediate configuration update.
app.MapPost("/api/update_config", async (HttpContext context, IConfigurationRefresherProvider refresherProvider, ILogger<Program> logger) =>
{
logger.LogInformation($"Entered update_config...");
var refresher = refresherProvider.Refreshers.First();
var data = await BinaryData.FromStreamAsync(context.Request.Body);
var eventGridEvent = EventGridEvent.Parse(data);
// Handle system events
if (eventGridEvent.TryGetSystemEventData(out object eventData))
{
// Handle the subscription validation event. This is needed to register this webhook during event subsscription creation.
if (eventData is SubscriptionValidationEventData subscriptionValidationEventData)
{
var responseData = new SubscriptionValidationResponse()
{
ValidationResponse = subscriptionValidationEventData.ValidationCode
};
await context.Response.WriteAsync(JsonSerializer.Serialize(responseData));
}
if (eventData is AppConfigurationKeyValueModifiedEventData)
{
logger.LogInformation($"Updating config data...");
eventGridEvent.TryCreatePushNotification(out PushNotification pushNotification);
// Invalidate cached config
refresher.ProcessPushNotification(pushNotification);
// Also tried this, but it doesn't update the config
// refresher.SetDirty(TimeSpan.FromSeconds(1));
// await Task.Delay(TimeSpan.FromSeconds(1));
var result = await refresher.TryRefreshAsync();
if (result)
{
logger.LogInformation("Config has been updated");
}
}
}
});
app.Run();
А это класс настроек:
public class Settings
{
public string Key { get; set; } = null!;
public string Sentinel { get; set; } = null!;
}
Когда я меняю ключ в конфигурации приложения Azure, я вижу, что обработчик событий выполнен, и я вижу следующие сообщения в журналах приложений:
Entered update_config...
Trying to update config settings...
Result is True
Но когда я использую конечную точку GET, я вижу предыдущее значение.
Обновление 1. Я обнаружил, что если я добавлю параметры «Ключ» в метод refreshOptions.Register, то кеш конфигурации станет недействительным, и я получил новое значение ключа из Azure, поэтому я внес это изменение в раздел ConfigureRefresh:
.ConfigureRefresh(refreshOptions =>
refreshOptions.Register("MyApp:Settings:Key", refreshAll: true)
.SetCacheExpiration(TimeSpan.FromDays(30)));
Но мне кажется не очевидным, зачем мне прописывать каждый конфигурационный ключ в RefreshOptions?
Обновление 2: я только что попытался полностью удалить обработчик и проверить, что будет, если я изменю значение ключа в конфигурации приложения. При опросе моей конечной точки GET я заметил, что значение изменилось через 20-30 минут, однако срок действия был установлен на 30 дней. Я проверяю, что за это время служба приложений не была перезапущена. Означает ли это, что этот срок действия ограничен внутренне?
Последующие вопросы:
- Можно ли указать, что мне нужно следить за всеми ключами в конфигурации?
- Могу ли я полностью отключить опрос конфигурации приложения и кэширование конфигурации, если у меня есть веб-перехватчик для обновления ключей и значений? В настоящее время я вижу, что это не сработает, если я удалю разделы ConfigureRefresh.
- Почему мне нужно явно аннулировать кеш конфигурации перед вызовом await Refresh.TryRefreshAsync();? Я ожидал, что эта недействительность должна быть внутри метода TryRefreshAsync.
1 ответ
Модель push-уведомлений в конфигурации приложений предназначена для уведомления об изменениях конфигурации. Он НЕ предназначен для доставки фактической конфигурации. Только приложение знает, какой набор конфигураций загрузить и при каких условиях конфигурация должна быть перезагружена. Поэтому само по себе уведомление об изменении не должно инициировать обновление конфигурации. Это обеспечивает согласованность конфигурации с приложением.
Идея состоит в том, что сначала вы сообщаете своему приложению, какую конфигурацию загружать и какую конфигурацию отслеживать для перезагрузки. Это та же установка, что и для модели опроса. Разница лишь в том, что вы устанавливаете гораздо больший интервал опроса. Затем, когда приходит уведомление об изменении, ваше приложение сбрасывает время ожидания мониторинга и немедленно отправляет запрос в Конфигурацию приложения для ключа, который он настроен для мониторинга. Если ключ изменен, он перезагрузит конфигурацию; в противном случае он ничего не сделает.
Надеюсь, вышеизложенное объясняет, почему вы видите то, что видите. В вашем случае, если ваше приложение настроено на перезагрузку конфигурации только в случае изменения ключа дозорного, вы должны внести изменения в ключ дозорного для перезагрузки конфигурации. Когда вы вносите изменения в другие ключи, хотя они и запускают push-уведомления для вашего приложения, с точки зрения вашего приложения, оно не готово к перезагрузке конфигурации, поскольку ключ-сигнализатор не изменен. Таким образом, push-уведомления других клавиш будут эффективно игнорироваться.
Надеюсь, это поможет. Я настоятельно рекомендую вам прочитать обсуждение в разделе документа Регистрация обработчика событий для перезагрузки данных из конфигурации приложения , чтобы узнать некоторые подробности.