diff --git a/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs b/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs
index dbaa1200..91be7d6e 100644
--- a/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs
+++ b/src/Microsoft.FeatureManagement/ConfigurationFeatureDefinitionProvider.cs
@@ -15,7 +15,7 @@ namespace Microsoft.FeatureManagement
///
/// A feature definition provider that pulls feature definitions from the .NET Core system.
///
- sealed class ConfigurationFeatureDefinitionProvider : IFeatureDefinitionProvider, IDisposable
+ sealed class ConfigurationFeatureDefinitionProvider : IFeatureDefinitionProvider, IDisposable, IFeatureDefinitionProviderCacheable
{
private const string FeatureFiltersSectionName = "EnabledFor";
private const string RequirementTypeKeyword = "RequirementType";
diff --git a/src/Microsoft.FeatureManagement/FeatureManagementOptions.cs b/src/Microsoft.FeatureManagement/FeatureManagementOptions.cs
index 49350ff9..329ddfc3 100644
--- a/src/Microsoft.FeatureManagement/FeatureManagementOptions.cs
+++ b/src/Microsoft.FeatureManagement/FeatureManagementOptions.cs
@@ -24,14 +24,5 @@ public class FeatureManagementOptions
/// The default value is true.
///
public bool IgnoreMissingFeatures { get; set; } = true;
-
- ///
- /// Controls the cache lifetime of settings bound by in the feature management cache.
- /// By default, this cache is off, with a ttl of .
- /// To enable caching of filter parameters, a non-zero ttl should be provided. A recommendation is five seconds.
- /// Increasing the value may cause an observed increase in memory footprint as items live longer.
- /// Lowering the value will decrease performance benefits yielded by caching bound parameters.
- ///
- public TimeSpan FilterSettingsCacheTtl { get; set; } = TimeSpan.Zero;
}
}
diff --git a/src/Microsoft.FeatureManagement/FeatureManager.cs b/src/Microsoft.FeatureManagement/FeatureManager.cs
index c34883ba..c0090fe6 100644
--- a/src/Microsoft.FeatureManagement/FeatureManager.cs
+++ b/src/Microsoft.FeatureManagement/FeatureManager.cs
@@ -25,7 +25,7 @@ class FeatureManager : IFeatureManager, IDisposable
private readonly ConcurrentDictionary _filterMetadataCache;
private readonly ConcurrentDictionary _contextualFeatureFilterCache;
private readonly FeatureManagementOptions _options;
- private readonly IMemoryCache _cache;
+ private readonly IMemoryCache _parametersCache;
private class ConfigurationCacheItem
{
@@ -47,12 +47,8 @@ public FeatureManager(
_logger = loggerFactory.CreateLogger();
_filterMetadataCache = new ConcurrentDictionary();
_contextualFeatureFilterCache = new ConcurrentDictionary();
- TryValidateOptions(options, out _options);
- _cache = new MemoryCache(
- new MemoryCacheOptions
- {
- ExpirationScanFrequency = _options.FilterSettingsCacheTtl
- });
+ _options = options?.Value ?? throw new ArgumentNullException(nameof(options));
+ _parametersCache = new MemoryCache(new MemoryCacheOptions());
}
public Task IsEnabledAsync(string feature)
@@ -75,7 +71,7 @@ public async IAsyncEnumerable GetFeatureNamesAsync()
public void Dispose()
{
- _cache.Dispose();
+ _parametersCache.Dispose();
}
private async Task IsEnabledAsync(string feature, TContext appContext, bool useAppContext)
@@ -227,14 +223,14 @@ private void BindSettings(IFeatureFilterMetadata filter, FeatureFilterEvaluation
//
// Check if settings already bound from configuration or the parameters have changed
- if (!_cache.TryGetValue(context.FeatureName, out cacheItem) ||
+ if (!_parametersCache.TryGetValue(context.FeatureName, out cacheItem) ||
cacheItem.Parameters != context.Parameters)
{
settings = binder.BindParameters(context.Parameters);
- if (_options.FilterSettingsCacheTtl > TimeSpan.Zero)
+ if (_featureDefinitionProvider is IFeatureDefinitionProviderCacheable)
{
- _cache.Set(
+ _parametersCache.Set(
context.FeatureName,
new ConfigurationCacheItem
{
@@ -243,7 +239,8 @@ private void BindSettings(IFeatureFilterMetadata filter, FeatureFilterEvaluation
},
new MemoryCacheEntryOptions
{
- AbsoluteExpirationRelativeToNow = _options.FilterSettingsCacheTtl
+ SlidingExpiration = TimeSpan.FromMinutes(5),
+ AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1)
});
}
}
@@ -327,17 +324,5 @@ private ContextualFeatureFilterEvaluator GetContextualFeatureFilter(string filte
return filter;
}
-
- private FeatureManagementOptions TryValidateOptions(IOptions options, out FeatureManagementOptions _options)
- {
- _options = options?.Value ?? throw new ArgumentNullException(nameof(options));
-
- if (_options.FilterSettingsCacheTtl < TimeSpan.Zero)
- {
- throw new ArgumentException("FilterSettingsCacheTtl option must be greater than or equal to TimeSpan.Zero.");
- }
-
- return _options;
- }
}
}
diff --git a/src/Microsoft.FeatureManagement/IFeatureDefinitionProviderCacheable.cs b/src/Microsoft.FeatureManagement/IFeatureDefinitionProviderCacheable.cs
new file mode 100644
index 00000000..973ec079
--- /dev/null
+++ b/src/Microsoft.FeatureManagement/IFeatureDefinitionProviderCacheable.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Microsoft.FeatureManagement
+{
+ public interface IFeatureDefinitionProviderCacheable
+ {
+ }
+}
diff --git a/tests/Tests.FeatureManagement/FeatureManagement.cs b/tests/Tests.FeatureManagement/FeatureManagement.cs
index 08b092ce..a2c45c31 100644
--- a/tests/Tests.FeatureManagement/FeatureManagement.cs
+++ b/tests/Tests.FeatureManagement/FeatureManagement.cs
@@ -7,7 +7,6 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Configuration.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.FeatureManagement;
using Microsoft.FeatureManagement.FeatureFilters;
@@ -876,11 +875,6 @@ public async Task BindsFeatureFlagSettings()
}
});
- services.Configure(options =>
- {
- options.FilterSettingsCacheTtl = TimeSpan.FromSeconds(5);
- });
-
services.AddSingleton(definitionProvider)
.AddSingleton(new ConfigurationBuilder().Build())
.AddFeatureManagement()
diff --git a/tests/Tests.FeatureManagement/InMemoryFeatureDefinitionProvider.cs b/tests/Tests.FeatureManagement/InMemoryFeatureDefinitionProvider.cs
index 91cbcefd..fe613254 100644
--- a/tests/Tests.FeatureManagement/InMemoryFeatureDefinitionProvider.cs
+++ b/tests/Tests.FeatureManagement/InMemoryFeatureDefinitionProvider.cs
@@ -6,7 +6,7 @@
namespace Tests.FeatureManagement
{
- class InMemoryFeatureDefinitionProvider : IFeatureDefinitionProvider
+ class InMemoryFeatureDefinitionProvider : IFeatureDefinitionProvider, IFeatureDefinitionProviderCacheable
{
private IEnumerable _definitions;