BrighterCommand / BrighterCommand/Brighter

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

Open
#3,053 1 comment 2 reactions 2 assignees Claimed by @iancooper View on GitHub
0 - Backlog feature request V10.X
Dominant language
C#
Stars
2.5k
Forks
296
Avg merge
1d 11h
Merged PRs (30d)
21

Description

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 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 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)]`

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.