Skip to content

Commit

Permalink
Adds GetFeatureNamesAsync to IVariantFeatureManager and uses the inte…
Browse files Browse the repository at this point in the history
…rface in FeatureManagerSnapshot (#270)
  • Loading branch information
rossgrambo authored Oct 4, 2023
1 parent b1b1562 commit b747bb4
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
14 changes: 11 additions & 3 deletions src/Microsoft.FeatureManagement/FeatureManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

Expand Down Expand Up @@ -145,11 +146,18 @@ private async Task<bool> IsEnabledWithVariantsAsync<TContext>(string feature, TC
return isFeatureEnabled;
}

public async IAsyncEnumerable<string> GetFeatureNamesAsync()
public IAsyncEnumerable<string> GetFeatureNamesAsync()
{
await foreach (FeatureDefinition featureDefintion in _featureDefinitionProvider.GetAllFeatureDefinitionsAsync().ConfigureAwait(false))
return GetFeatureNamesAsync(CancellationToken.None);
}

public async IAsyncEnumerable<string> GetFeatureNamesAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
await foreach (FeatureDefinition featureDefinition in _featureDefinitionProvider.GetAllFeatureDefinitionsAsync().ConfigureAwait(false))
{
yield return featureDefintion.Name;
cancellationToken.ThrowIfCancellationRequested();

yield return featureDefinition.Name;
}
}

Expand Down
22 changes: 14 additions & 8 deletions src/Microsoft.FeatureManagement/FeatureManagerSnapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -15,23 +16,28 @@ namespace Microsoft.FeatureManagement
/// </summary>
class FeatureManagerSnapshot : IFeatureManagerSnapshot, IVariantFeatureManagerSnapshot
{
private readonly FeatureManager _featureManager;
private readonly IVariantFeatureManager _featureManager;
private readonly ConcurrentDictionary<string, Task<bool>> _flagCache = new ConcurrentDictionary<string, Task<bool>>();
private readonly ConcurrentDictionary<string, Variant> _variantCache = new ConcurrentDictionary<string, Variant>();
private IEnumerable<string> _featureNames;

public FeatureManagerSnapshot(FeatureManager featureManager)
public FeatureManagerSnapshot(IVariantFeatureManager featureManager)
{
_featureManager = featureManager ?? throw new ArgumentNullException(nameof(featureManager));
}

public async IAsyncEnumerable<string> GetFeatureNamesAsync()
public IAsyncEnumerable<string> GetFeatureNamesAsync()
{
return GetFeatureNamesAsync(CancellationToken.None);
}

public async IAsyncEnumerable<string> GetFeatureNamesAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
if (_featureNames == null)
{
var featureNames = new List<string>();

await foreach (string featureName in _featureManager.GetFeatureNamesAsync().ConfigureAwait(false))
await foreach (string featureName in _featureManager.GetFeatureNamesAsync(cancellationToken).ConfigureAwait(false))
{
featureNames.Add(featureName);
}
Expand All @@ -49,28 +55,28 @@ public Task<bool> IsEnabledAsync(string feature)
{
return _flagCache.GetOrAdd(
feature,
(key) => _featureManager.IsEnabledAsync(key));
(key) => _featureManager.IsEnabledAsync(key, CancellationToken.None));
}

public Task<bool> IsEnabledAsync<TContext>(string feature, TContext context)
{
return _flagCache.GetOrAdd(
feature,
(key) => _featureManager.IsEnabledAsync(key, context));
(key) => _featureManager.IsEnabledAsync(key, context, CancellationToken.None));
}

public Task<bool> IsEnabledAsync(string feature, CancellationToken cancellationToken)
{
return _flagCache.GetOrAdd(
feature,
(key) => _featureManager.IsEnabledAsync(key));
(key) => _featureManager.IsEnabledAsync(key, cancellationToken));
}

public Task<bool> IsEnabledAsync<TContext>(string feature, TContext context, CancellationToken cancellationToken)
{
return _flagCache.GetOrAdd(
feature,
(key) => _featureManager.IsEnabledAsync(key, context));
(key) => _featureManager.IsEnabledAsync(key, context, cancellationToken));
}

public async ValueTask<Variant> GetVariantAsync(string feature, CancellationToken cancellationToken)
Expand Down
11 changes: 9 additions & 2 deletions src/Microsoft.FeatureManagement/IVariantFeatureManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Threading.Tasks;
using System.Threading;
using Microsoft.FeatureManagement.FeatureFilters;
using System.Collections.Generic;

namespace Microsoft.FeatureManagement
{
Expand All @@ -12,6 +13,12 @@ namespace Microsoft.FeatureManagement
/// </summary>
public interface IVariantFeatureManager
{
/// <summary>
/// Retrieves a list of feature names registered in the feature manager.
/// </summary>
/// <returns>An enumerator which provides asynchronous iteration over the feature names registered in the feature manager.</returns>
IAsyncEnumerable<string> GetFeatureNamesAsync(CancellationToken cancellationToken);

/// <summary>
/// Checks whether a given feature is enabled.
/// </summary>
Expand All @@ -30,15 +37,15 @@ public interface IVariantFeatureManager
Task<bool> IsEnabledAsync<TContext>(string feature, TContext context, CancellationToken cancellationToken);

/// <summary>
/// Gets the assigned variant for a specfic feature.
/// Gets the assigned variant for a specific feature.
/// </summary>
/// <param name="feature">The name of the feature to evaluate.</param>
/// <param name="cancellationToken">The cancellation token to cancel the operation.</param>
/// <returns>A variant assigned to the user based on the feature's configured allocation.</returns>
ValueTask<Variant> GetVariantAsync(string feature, CancellationToken cancellationToken);

/// <summary>
/// Gets the assigned variant for a specfic feature.
/// Gets the assigned variant for a specific feature.
/// </summary>
/// <param name="feature">The name of the feature to evaluate.</param>
/// <param name="context">An instance of <see cref="TargetingContext"/> used to evaluate which variant the user will be assigned.</param>
Expand Down

0 comments on commit b747bb4

Please sign in to comment.