BrighterCommand / Brighter

A framework for building messaging apps with .NET and C#.

Home Page:https://www.goparamore.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Feature] First class support for Azure App Configuration Feature Management

Jonny-Freemarket opened this issue · comments

Azure App Configuration has a Feature Manager that allows you to toggle features on and off. These feature switch values can refreshed as part of the HTTP pipeline in ASP.NET Core, or by explicitly refreshing them with the Azure App Configuration SDK.

Brighter has the IAmAFeatureSwitchRegistry that allows for the Azure App Configuration Feature Manager to be used to control whether a Brighter handler runs or not in the pipeline. The basic building blocks of this are:

Configure the Azure App Configuration SDK to use Feature Manager

builder.Configuration
          .AddAzureAppConfiguration(options =>
          {
             ...
              
              options.Connect(..)
                  ...
                  .UseFeatureFlags(opts => opts.Select("YourServiceName_*", "flags"))
                  .ConfigureRefresh(refresh => refresh.Register("FeatureManagement").SetCacheExpiration(TimeSpan.FromSeconds(30)));
              
              builder.Services.AddSingleton(options.GetRefresher());
          });

Implement concrete IAmAFeatureSwitchRegistry

public class AppConfigurationFeatureSwitchRegistry : IAmAFeatureSwitchRegistry
{
    private readonly IFeatureManagerSnapshot _featureManager;
    private readonly IConfigurationRefresher _configurationRefresher;

    public AppConfigurationFeatureSwitchRegistry(IFeatureManagerSnapshot featureManager, IConfigurationRefresher configurationRefresher)
    {
        _featureManager = featureManager;
        _configurationRefresher = configurationRefresher;
    }

    public FeatureSwitchStatus StatusOf(Type handler)
    {
        ...
        // Removed for brevity
        ...
    }

    // As Brighter handlers not always part of an HTTP pipeline we have to force a refresh of the feature flags
    private async Task<bool?> CheckFeatureFlags(string feature)
    {
        await _configurationRefresher.TryRefreshAsync();

        await foreach (var featureName in _featureManager.GetFeatureNamesAsync())
        {
            if (featureName == feature)
                return await _featureManager.IsEnabledAsync(feature);
        }

        return null;
    }

    // If I feature switch is not found, but the handler is decorated with the attribute then
    // then the handler will still be allowed to run
    public MissingConfigStrategy MissingConfigStrategy { get; set; } = MissingConfigStrategy.SilentOn;
}

Decorating Brighter Handler with Feature Switch

...
[FeatureSwitchAsync(typeof(YourCommandHandler), FeatureSwitchStatus.Config, 0)]
public override async Task<YourCommand> HandleAsync(YourCommandmessage, CancellationToken cancellationToken = new CancellationToken())
{
    ...
}
...

Proposed Change

  • We wrap up the required plumbing into extension methods / bundled classes
  • Introduce a new Brighter attribute to use instead of the [FeatureSwitchAsync(..)] attribute, something like:

[AppConfigurationFeatureSwitchAsync(nameof(YourCommandHandler), 0)]

Looks good to me.