public Startup(IConfiguration config) { // Use JSON property names in validation. ValidationArgs.DefaultUseJsonNames = true; // Load the cache policies. CachePolicyManager.SetFromCachePolicyConfig(config.GetSection("BeefCaching").Get <CachePolicyConfig>()); CachePolicyManager.StartFlushTimer(CachePolicyManager.TenMinutes, CachePolicyManager.FiveMinutes); // Register the ReferenceData provider. RefData.ReferenceDataManager.Register(new ReferenceDataProvider()); // Register the database. Database.Register(() => new Database(WebApiStartup.GetConnectionString(config, "BeefDemo"))); // Register the DocumentDb/CosmosDb client. CosmosDb.Register(() => { var cs = config.GetSection("CosmosDb"); return(new CosmosDb(new Cosmos.CosmosClient(cs.GetValue <string>("EndPoint"), cs.GetValue <string>("AuthKey")), cs.GetValue <string>("Database"))); }); // Register the test OData service. TestOData.Register(() => new TestOData(WebApiStartup.GetConnectionString(config, "TestOData"))); // Default the page size. PagingArgs.DefaultTake = config.GetValue <int>("BeefDefaultPageSize"); // Configure the Service Agents from the configuration and register. var sac = config.GetSection("BeefServiceAgents").Get <WebApiServiceAgentConfig>(); sac?.RegisterAll(); }
/// <summary> /// Initializes a new instance of the <see cref="Startup"/> class. /// </summary> /// <param name="config">The <see cref="IConfiguration"/>.</param> public Startup(IConfiguration config) { // Use JSON property names in validation. ValidationArgs.DefaultUseJsonNames = true; // Load the cache policies. CachePolicyManager.SetFromCachePolicyConfig(config.GetSection("BeefCaching").Get <CachePolicyConfig>()); CachePolicyManager.StartFlushTimer(CachePolicyManager.TenMinutes, CachePolicyManager.FiveMinutes); // Register the ReferenceData provider. Beef.RefData.ReferenceDataManager.Register(new ReferenceDataProvider()); #if (implement_database || implement_entityframework) // Register the database. Database.Register(() => new Database(WebApiStartup.GetConnectionString(config, "Database"))); #endif #if (implement_cosmos) // Register the DocumentDb/CosmosDb client. CosmosDb.Register(() => { var cs = config.GetSection("CosmosDb"); return(new CosmosDb(new Cosmos.CosmosClient(cs.GetValue <string>("EndPoint"), cs.GetValue <string>("AuthKey")), cs.GetValue <string>("Database"))); }); #endif // Default the page size. PagingArgs.DefaultTake = config.GetValue <int>("BeefDefaultPageSize"); }
/// <summary> /// Registers an internal <b>Policy Key</b> (using the <see cref="InternalPolicyKeyFormat"/>) with a <see cref="NoCachePolicy"/> to ensure always invoked; /// it is then expected that the <see cref="OnFlushCache(bool)"/> will handle policy expiration specifically. /// </summary> protected void RegisterInternalPolicyKey() { var overridePolicyKey = string.Format(InternalPolicyKeyFormat, PolicyKey); CachePolicyManager.Register(this, overridePolicyKey); CachePolicyManager.Set(overridePolicyKey, new NoCachePolicy()); }
/// <summary> /// Registers an internal <b>Policy Key</b> (using the <see cref="InternalPolicyKeyFormat"/>) with a <see cref="NoCachePolicy"/> to ensure always invoked; /// it is then expected that the <see cref="OnFlushCache(bool)"/> will handle policy expiration specifically. /// </summary> protected void RegisterInternalPolicyKey() { var overridePolicyKey = string.Format(System.Globalization.CultureInfo.InvariantCulture, InternalPolicyKeyFormat, PolicyKey); CachePolicyManager.Register(this, overridePolicyKey); CachePolicyManager.Set(overridePolicyKey, new NoCachePolicy()); }
private void ConcurrenyRun() { int key1Count = 0; int key2Count = 0; CachePolicyManager.Reset(); var mtc = new TwoKeyValueCache <int, string, string>( (key1) => { key1Count++; Thread.Sleep(10); return((key1 == 99) ? (false, null, null) : (true, key1.ToString(), $"x{key1}x")); }, (key2) => { key2Count++; Thread.Sleep(10); return(true, int.Parse(key2), $"x{int.Parse(key2)}x"); }, "TwoKeyValueCacheTest"); var tasks = new Task[8]; tasks[0] = Task.Run(() => mtc.GetByKey1(1)); tasks[1] = Task.Run(() => mtc.GetByKey2("1")); tasks[2] = Task.Run(() => mtc.GetByKey1(1)); tasks[3] = Task.Run(() => mtc.GetByKey2("1")); tasks[4] = Task.Run(() => mtc.GetByKey1(1)); tasks[5] = Task.Run(() => mtc.GetByKey2("1")); tasks[6] = Task.Run(() => mtc.GetByKey1(1)); tasks[7] = Task.Run(() => mtc.GetByKey2("1")); Task.WaitAll(tasks); Assert.AreEqual(1, key1Count); Assert.AreEqual(1, key2Count); }
public void PolicyManager() { CachePolicyManager.Reset(); var dsc = new DictionarySetCache <int, string>((data) => new KeyValuePair <int, string>[] { new KeyValuePair <int, string>(1, "1"), new KeyValuePair <int, string>(2, "2") }); Assert.IsNotNull(dsc.PolicyKey); Assert.AreEqual(0, dsc.Count); Assert.IsTrue(dsc.ContainsKey(1)); Assert.IsTrue(dsc.ContainsKey(2)); Assert.IsFalse(dsc.ContainsKey(3)); Assert.AreEqual(2, dsc.Count); var policy = new DailyCachePolicy(); CachePolicyManager.Set(dsc.PolicyKey, policy); var policy2 = dsc.GetPolicy(); Assert.IsNotNull(policy2); Assert.AreSame(policy, policy2); var pa = CachePolicyManager.GetPolicies(); Assert.AreEqual(1, pa.Length); CachePolicyManager.ForceFlush(); Assert.AreEqual(0, dsc.Count); Assert.IsTrue(dsc.ContainsKey(1)); Assert.IsTrue(dsc.ContainsKey(2)); Assert.IsFalse(dsc.ContainsKey(3)); Assert.AreEqual(2, dsc.Count); }
/// <summary> /// Initializes a new instance of the <see cref="Startup"/> class. /// </summary> /// <param name="config">The <see cref="IConfiguration"/>.</param> /// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param> public Startup(IConfiguration config, ILoggerFactory loggerFactory) { // Use JSON property names in validation; default the page size and determine whether unhandled exception details are to be included in the response. ValidationArgs.DefaultUseJsonNames = true; PagingArgs.DefaultTake = config.GetValue <int>("BeefDefaultPageSize"); WebApiExceptionHandlerMiddleware.IncludeUnhandledExceptionInResponse = config.GetValue <bool>("BeefIncludeExceptionInInternalServerError"); // Configure the logger. _logger = loggerFactory.CreateLogger("Logging"); Logger.RegisterGlobal((largs) => WebApiStartup.BindLogger(_logger, largs)); // Configure the cache policies. CachePolicyManager.SetFromCachePolicyConfig(config.GetSection("BeefCaching").Get <CachePolicyConfig>()); CachePolicyManager.StartFlushTimer(CachePolicyManager.TenMinutes, CachePolicyManager.FiveMinutes); #if (implement_database || implement_entityframework) // Register the database. AppNameDb.Register(() => new AppNameDb(WebApiStartup.GetConnectionString(config, "Database"))); #endif #if (implement_cosmos) // Register the DocumentDb/CosmosDb client. AppNameCosmosDb.Register(() => { var cs = config.GetSection("CosmosDb"); return(new AppNameCosmosDb(new CosmosClient(cs.GetValue <string>("EndPoint"), cs.GetValue <string>("AuthKey")), cs.GetValue <string>("Database"))); }); #endif // Register the ReferenceData provider. Beef.RefData.ReferenceDataManager.Register(new ReferenceDataProvider()); }
/// <summary> /// Initializes a new instance of the <see cref="Startup"/> class. /// </summary> /// <param name="config">The <see cref="IConfiguration"/>.</param> /// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param> public Startup(IConfiguration config, ILoggerFactory loggerFactory) { // Use JSON property names in validation; and determine whether unhandled exception details are to be included in the response. ValidationArgs.DefaultUseJsonNames = true; WebApiExceptionHandlerMiddleware.IncludeUnhandledExceptionInResponse = config.GetValue <bool>("BeefIncludeExceptionInInternalServerError"); // Add "page" and "page-size" to the supported paging query string parameters as defined by the CDR specification; and default the page size to 25 from config. WebApiQueryString.PagingArgsPageQueryStringNames.Add("page"); WebApiQueryString.PagingArgsTakeQueryStringNames.Add("page-size"); PagingArgs.DefaultTake = config.GetValue <int>("BeefDefaultPageSize"); // Configure the logger. _logger = loggerFactory.CreateLogger("Logging"); Logger.RegisterGlobal((largs) => WebApiStartup.BindLogger(_logger, largs)); // Configure the cache policies. CachePolicyManager.SetFromCachePolicyConfig(config.GetSection("BeefCaching").Get <CachePolicyConfig>()); CachePolicyManager.StartFlushTimer(CachePolicyManager.TenMinutes, CachePolicyManager.FiveMinutes); // Register the DocumentDb/CosmosDb client. CosmosDb.Register(() => { var cs = config.GetSection("CosmosDb"); return(new CosmosDb(new Microsoft.Azure.Cosmos.CosmosClient(cs.GetValue <string>("EndPoint"), cs.GetValue <string>("AuthKey")), cs.GetValue <string>("Database"))); }); // Register the ReferenceData provider. Beef.RefData.ReferenceDataManager.Register(new ReferenceDataProvider()); // Register the "customised" execution context. Beef.ExecutionContext.Register(() => new ExecutionContext()); }
/// <summary> /// Initializes a new instance of the <see cref="CacheCoreBase"/> class that automatically <see cref="CachePolicyManager.Register">registers</see> for centralised <see cref="CachePolicyManager.Flush"/> management. /// </summary> /// <param name="policyKey">The policy key used to determine the cache policy configuration (see <see cref="CachePolicyManager"/>); defaults to <see cref="Guid.NewGuid()"/> ensuring uniqueness.</param> /// <param name="doNotRegister">Indicates that the automatic <see cref="CachePolicyManager.Register"/> should not occur (inheriting class must perform).</param> protected CacheCoreBase(string?policyKey = null, bool doNotRegister = false) { PolicyKey = string.IsNullOrEmpty(policyKey) ? Guid.NewGuid().ToString() : policyKey; if (!doNotRegister) { CachePolicyManager.Register(this); } }
/// <summary> /// Disposes all resources (see <see cref="Flush(bool)"/>) and invokes the <see cref="CachePolicyManager.Unregister(string)"/> for the <see cref="PolicyKey"/>. /// </summary> public void Dispose() { lock (Lock) { Flush(true); CachePolicyManager.Unregister(PolicyKey); } }
public void PolicyManager() { CachePolicyManager.Reset(); var mtc = new TwoKeyValueCache <int, string, string>( (key1) => { return((key1 == 99) ? (false, null, null) : (true, key1.ToString(), $"x{key1}x")); }, (key2) => { return(true, int.Parse(key2), $"x{int.Parse(key2)}x"); }, "TwoKeyValueCacheTest"); Assert.IsTrue(mtc.TryGetByKey1(1, out string val)); Assert.IsTrue(mtc.TryGetByKey2("2", out val)); var pa = CachePolicyManager.GetPolicies(); Assert.AreEqual(2, pa.Length); // Check the internal nocachepolicy. var p0 = pa.Where(x => x.Key.StartsWith("TwoKeyValueCacheTest_")).SingleOrDefault(); Assert.IsNotNull(p0); Assert.IsInstanceOf(typeof(NoCachePolicy), p0.Value); // Check the default policy for type. var p1 = pa.Where(x => x.Key == "TwoKeyValueCacheTest").SingleOrDefault(); Assert.IsNotNull(p1); Assert.IsInstanceOf(typeof(NoExpiryCachePolicy), p1.Value); // Each value should have its own policy. var policy1 = mtc.GetPolicyByKey1(1); Assert.IsNotNull(policy1); Assert.IsInstanceOf(typeof(NoExpiryCachePolicy), policy1); var policy2 = mtc.GetPolicyByKey2("2"); Assert.IsNotNull(policy2); Assert.IsInstanceOf(typeof(NoExpiryCachePolicy), policy2); Assert.AreNotSame(policy1, policy2); // There should be no policy where item not found. Assert.IsNull(mtc.GetPolicyByKey1(3)); // Flush cache where not expired; nothing happens. mtc.Flush(); var v = mtc.GetByKey1(1); Assert.AreEqual("x1x", v); Assert.AreEqual(2, mtc.Count); // Force flush; should reload cache after. mtc.Flush(true); Assert.AreEqual(0, mtc.Count); Assert.IsFalse(mtc.ContainsKey1(1)); }
/// <summary> /// Reset (set up) the <see cref="TestSetUp"/> to a known initial state; will result in the <see cref="RegisterSetUp(Func{int, object, bool})">registered</see> set up function being executed. /// </summary> /// <param name="setUpIfAlreadyDone">Indicates whether to perform the setup if already done; defaults to <c>true</c>.</param> /// <param name="data">Optional data to be passed to the resgitered set up function.</param> /// <remarks>This also invokes the <see cref="CachePolicyManager.ForceFlush"/> and <see cref="DependencyGroupAttribute.Refresh"/>.</remarks> public static void Reset(bool setUpIfAlreadyDone = true, object?data = null) { lock (_lock) { if (!_registeredSetUpInvoked || setUpIfAlreadyDone) { ShouldContinueRunningTests = true; CachePolicyManager.ForceFlush(); DependencyGroupAttribute.Refresh(); _registeredSetUpData = data; _registeredSetUpInvoked = false; } } }
public void Concurrency() { var l = new object(); CachePolicyManager.Reset(); int i = 0; var mtc = new KeyValueCache <int, string>((key) => { lock (l) { i++; } TestContext.WriteLine($"GetValue {key} [{System.Threading.Thread.CurrentThread.ManagedThreadId}]"); System.Threading.Thread.Sleep(20); return(key.ToString()); }); // Set an execution context. var tasks = new Task[13]; tasks[0] = Task.Run(() => Timer(0, 1, () => { Assert.AreEqual(mtc[1], "1"); })); tasks[1] = Task.Run(() => Timer(1, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[2] = Task.Run(() => Timer(2, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[3] = Task.Run(() => Timer(3, 3, () => { Assert.AreEqual(mtc[3], "3"); })); tasks[4] = Task.Run(() => Timer(4, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[5] = Task.Run(() => Timer(5, 1, () => { Assert.AreEqual(mtc[1], "1"); })); tasks[6] = Task.Run(() => Timer(6, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[7] = Task.Run(() => Timer(7, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[8] = Task.Run(() => Timer(8, 3, () => { Assert.AreEqual(mtc[3], "3"); })); tasks[9] = Task.Run(() => Timer(9, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[10] = Task.Run(() => Timer(10, 1, () => { Assert.AreEqual(mtc[1], "1"); })); tasks[11] = Task.Run(() => Timer(11, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[12] = Task.Run(() => Timer(12, 3, () => { Assert.AreEqual(mtc[3], "3"); })); Task.WaitAll(tasks); Assert.AreEqual(3, i); TestContext.WriteLine("Round 2"); tasks = new Task[13]; tasks[0] = Task.Run(() => Timer(0, 1, () => { Assert.AreEqual(mtc[1], "1"); })); tasks[1] = Task.Run(() => Timer(1, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[2] = Task.Run(() => Timer(2, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[3] = Task.Run(() => Timer(3, 3, () => { Assert.AreEqual(mtc[3], "3"); })); tasks[4] = Task.Run(() => Timer(4, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[5] = Task.Run(() => Timer(5, 1, () => { Assert.AreEqual(mtc[1], "1"); })); tasks[6] = Task.Run(() => Timer(6, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[7] = Task.Run(() => Timer(7, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[8] = Task.Run(() => Timer(8, 3, () => { Assert.AreEqual(mtc[3], "3"); })); tasks[9] = Task.Run(() => Timer(9, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[10] = Task.Run(() => Timer(10, 1, () => { Assert.AreEqual(mtc[1], "1"); })); tasks[11] = Task.Run(() => Timer(11, 2, () => { Assert.AreEqual(mtc[2], "2"); })); tasks[12] = Task.Run(() => Timer(12, 3, () => { Assert.AreEqual(mtc[3], "3"); })); Task.WaitAll(tasks); Assert.AreEqual(3, i); }
public void UnregisterAndReuse() { CachePolicyManager.Reset(); var dsc = new DictionarySetCache <int, string>((data) => new KeyValuePair <int, string>[] { new KeyValuePair <int, string>(1, "1"), new KeyValuePair <int, string>(2, "2") }, "CachePolicyManagerTest"); // Asserting will load the cache on first access. Assert.AreEqual("1", dsc[1]); Assert.AreEqual("2", dsc[2]); dsc.Dispose(); // Unregister so the policy name can be reused. //CachePolicyManager.Unregister(dsc.PolicyKey); dsc = new DictionarySetCache <int, string>((data) => new KeyValuePair <int, string>[] { new KeyValuePair <int, string>(1, "10"), new KeyValuePair <int, string>(2, "20") }, "CachePolicyManagerTest"); Assert.AreEqual("10", dsc[1]); Assert.AreEqual("20", dsc[2]); }
/// <summary> /// Releases the unmanaged resources used by the <see cref="CacheCoreBase"/> and optionally releases the managed resources. /// </summary> /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> protected virtual void Dispose(bool disposing) { if (_disposed) { return; } if (disposing) { lock (Lock) { Flush(true); CachePolicyManager.Unregister(PolicyKey); } } _disposed = true; }
public Startup(IConfiguration config) { // Use JSON property names in validation. ValidationArgs.DefaultUseJsonNames = true; // Load the cache policies. CachePolicyManager.SetFromCachePolicyConfig(config.GetSection("BeefCaching").Get <CachePolicyConfig>()); CachePolicyManager.StartFlushTimer(CachePolicyManager.TenMinutes, CachePolicyManager.FiveMinutes); // Register the ReferenceData provider. RefData.ReferenceDataManager.Register(new ReferenceDataProvider()); // Register the database. Database.Register(() => new Database(WebApiStartup.GetConnectionString(config, "BeefDemo"))); Beef.Data.Database.DatabaseInvoker.Default = new Beef.Data.Database.SqlRetryDatabaseInvoker(); // Register the DocumentDb/CosmosDb client. CosmosDb.Register(() => { var cs = config.GetSection("CosmosDb"); return(new CosmosDb(new Cosmos.CosmosClient(cs.GetValue <string>("EndPoint"), cs.GetValue <string>("AuthKey")), cs.GetValue <string>("Database"))); }); // Register the test OData services. TestOData.Register(() => new TestOData(new Uri(WebApiStartup.GetConnectionString(config, "TestOData")))); TripOData.Register(() => new TripOData(new Uri(WebApiStartup.GetConnectionString(config, "TripOData")))); // Default the page size. PagingArgs.DefaultTake = config.GetValue <int>("BeefDefaultPageSize"); // Configure the Service Agents from the configuration and register. var sac = config.GetSection("BeefServiceAgents").Get <WebApiServiceAgentConfig>(); sac?.RegisterAll(); // Set up the event publishing to event hubs. if (config.GetValue <bool>("EventHubPublishing")) { var ehc = EventHubClient.CreateFromConnectionString(config.GetValue <string>("EventHubConnectionString")); ehc.RetryPolicy = RetryPolicy.Default; var ehp = new EventHubPublisher(ehc); Event.Register((events) => ehp.Publish(events)); } }
/// <summary> /// Adds a singleton service to instantiate a new <see cref="CachePolicyManager"/> instance with the specified <paramref name="config"/>, <paramref name="flushDueTime"/> and <paramref name="flushPeriod"/>. /// </summary> /// <param name="services">The <see cref="IServiceCollection"/>.</param> /// <param name="config">The optional <see cref="CachePolicyConfig"/>.</param> /// <param name="flushDueTime">The optional amount of time to delay before <see cref="CachePolicyManager.Flush"/> is invoked for the first time (defaults to <see cref="CachePolicyManager.TenMinutes"/>).</param> /// <param name="flushPeriod">The optional time interval between subsequent invocations of <see cref="CachePolicyManager.Flush"/> (defaults to <see cref="CachePolicyManager.FiveMinutes"/>).</param> /// <returns>The <see cref="IServiceCollection"/> for fluent-style method-chaining.</returns> /// <remarks>The The <see cref="CachePolicyManager"/> enables the centralised management of <see cref="ICachePolicy"/> caches.</remarks> public static IServiceCollection AddBeefCachePolicyManager(this IServiceCollection services, CachePolicyConfig?config = null, TimeSpan?flushDueTime = null, TimeSpan?flushPeriod = null) { if (services == null) { throw new ArgumentNullException(nameof(services)); } return(services.AddSingleton(_ => { var cpm = new CachePolicyManager(); if (config != null) { cpm.SetFromCachePolicyConfig(config); } cpm.StartFlushTimer(flushDueTime ?? CachePolicyManager.TenMinutes, flushPeriod ?? CachePolicyManager.FiveMinutes); return cpm; })); }
public void Flush() { CachePolicyManager.Reset(); using (var dsc = new DictionarySetCache <int, string>((data) => new KeyValuePair <int, string>[] { new KeyValuePair <int, string>(1, "1"), new KeyValuePair <int, string>(2, "2") })) { var policy = new DailyCachePolicy(); CachePolicyManager.Set(dsc.PolicyKey, policy); Assert.IsTrue(dsc.ContainsKey(1)); Assert.IsTrue(dsc.ContainsKey(2)); Assert.AreEqual(1, dsc.GetPolicy().Hits); dsc.Flush(true); Assert.IsTrue(dsc.ContainsKey(1)); Assert.IsTrue(dsc.ContainsKey(2)); Assert.AreEqual(1, dsc.GetPolicy().Hits); } }
public void Configure(IWebJobsBuilder builder) { var config = builder.GetConfiguration(typeof(Startup).Assembly, environmentVariablesPrefix: "Beef_"); // Load the cache policies. CachePolicyManager.SetFromCachePolicyConfig(config.GetSection("BeefCaching").Get <CachePolicyConfig>()); CachePolicyManager.StartFlushTimer(CachePolicyManager.TenMinutes, CachePolicyManager.FiveMinutes); // Register the ReferenceData provider. RefData.ReferenceDataManager.Register(new ReferenceDataProvider()); // Register the database. Database.Register(() => new Database(config.GetConnectionString("BeefDemo"))); // Register the DocumentDb/CosmosDb client. CosmosDb.Register(() => { var cs = config.GetSection("CosmosDb"); return(new CosmosDb(new Microsoft.Azure.Cosmos.CosmosClient(cs.GetValue <string>("EndPoint"), cs.GetValue <string>("AuthKey")), cs.GetValue <string>("Database"))); }); }
public void SetCachePolicyManager() { var cpc = new CachePolicyConfig { Policies = new CachePolicyConfig.CachePolicyConfigPolicy[] { new CachePolicyConfig.CachePolicyConfigPolicy { Name = "MyTest", Policy = "Beef.Caching.Policy.SlidingCachePolicy, Beef.Core", Properties = new CachePolicyConfig.CachePolicyConfigPolicyProperty[] { new CachePolicyConfig.CachePolicyConfigPolicyProperty { Name = "Duration", Value = "00:30:00" }, new CachePolicyConfig.CachePolicyConfigPolicyProperty { Name = "MaxDuration", Value = "02:00:00" }, new CachePolicyConfig.CachePolicyConfigPolicyProperty { Name = "RandomizerOffset", Value = "00:10:00" } }, Caches = new string[] { "BlahX" } } } }; CachePolicyManager.SetFromCachePolicyConfig(cpc); var pol = CachePolicyManager.Get("BlahX"); Assert.NotNull(pol); Assert.IsInstanceOf <SlidingCachePolicy>(pol); var scp = (SlidingCachePolicy)pol; Assert.AreEqual(new TimeSpan(00, 30, 00), scp.Duration); Assert.AreEqual(new TimeSpan(02, 00, 00), scp.MaxDuration); Assert.AreEqual(new TimeSpan(00, 10, 00), scp.RandomizerOffset); }
/// <summary> /// Adds a singleton service to instantiate a new <see cref="CachePolicyManager"/> instance with the specified <paramref name="config"/> and starts the corresponding <see cref="CachePolicyManagerServiceHost"/> with the <paramref name="firstInterval"/> and <paramref name="interval"/>. /// </summary> /// <param name="services">The <see cref="IServiceCollection"/>.</param> /// <param name="config">The optional <see cref="CachePolicyConfig"/>.</param> /// <param name="firstInterval">The optional <see cref="CachePolicyManagerServiceHost"/> <see cref="TimerHostedServiceBase.FirstInterval"/> before <see cref="CachePolicyManager.Flush"/> is invoked for the first time (defaults to <see cref="CachePolicyManager.TenMinutes"/>).</param> /// <param name="interval">The optional <see cref="CachePolicyManagerServiceHost"/> <see cref="TimerHostedServiceBase.FirstInterval"/> between subsequent invocations of <see cref="CachePolicyManager.Flush"/> (defaults to <see cref="CachePolicyManager.FiveMinutes"/>).</param> /// <param name="useCachePolicyManagerTimer">Indicates whether the <see cref="CachePolicyManager.StartFlushTimer(TimeSpan, TimeSpan, ILogger{CachePolicyManager}?)"/> should be used; versus, being managed via <c>"IServiceCollection.AddHostedService"</c> <see cref="CachePolicyManagerServiceHost"/> (default).</param> /// <returns>The <see cref="IServiceCollection"/> for fluent-style method-chaining.</returns> /// <remarks>The <see cref="CachePolicyManager"/> enables the centralised management of <see cref="ICachePolicy"/> caches.</remarks> public static IServiceCollection AddBeefCachePolicyManager(this IServiceCollection services, CachePolicyConfig?config = null, TimeSpan?firstInterval = null, TimeSpan?interval = null, bool useCachePolicyManagerTimer = false) { if (services == null) { throw new ArgumentNullException(nameof(services)); } var cpm = new CachePolicyManager(); if (config != null) { cpm.SetFromCachePolicyConfig(config); } firstInterval ??= CachePolicyManager.TenMinutes; interval ??= CachePolicyManager.FiveMinutes; services.AddSingleton(sp => { if (useCachePolicyManagerTimer) { cpm.StartFlushTimer(firstInterval.Value, interval.Value, sp.GetService <ILogger <CachePolicyManager> >()); } return(cpm); }); if (!useCachePolicyManagerTimer) { services.AddHostedService(sp => new CachePolicyManagerServiceHost(cpm, sp, sp.GetRequiredService <ILogger <CachePolicyManager> >()) { FirstInterval = firstInterval, Interval = interval.Value }); } return(services); }
public CacheProcessor(CachePolicyManager cachePolicyManager, ICacheProvider cacheProvider) { _cachePolicyManager = cachePolicyManager; _cacheProvider = cacheProvider; }
/// <summary> /// Gets the <see cref="ICachePolicy"/> (as specified via the constructor, or from the centralised <see cref="CachePolicyManager"/> using the <see cref="PolicyKey"/>). /// </summary> public ICachePolicy GetPolicy() => _policy ?? CachePolicyManager.Get(PolicyKey);
public void CreateAndGetWithForceFlush() { CachePolicyManager.IsInternalTracingEnabled = true; CachePolicyManager.Reset(); // Initialize the cache. var mtc = new MultiTenantCache <KeyValueCache <int, string> >((g, p) => { if (g.Equals(ToGuid(1))) { return(new KeyValueCache <int, string>(p, (k) => k.ToString())); } else { return(new KeyValueCache <int, string>(p, (k) => "X" + k.ToString())); } }, "MultiTenantCacheTest"); var pa = CachePolicyManager.GetPolicies(); Assert.AreEqual(1, pa.Length); // Check the internal nocachepolicy. var p0 = pa.Where(x => x.Key.StartsWith("MultiTenantCacheTest_")).SingleOrDefault(); Assert.IsNotNull(p0); Assert.IsInstanceOf(typeof(NoCachePolicy), p0.Value); // Check that the cache is empty. Assert.IsFalse(mtc.Contains(ToGuid(1))); Assert.AreEqual(0, mtc.Count); mtc.Remove(ToGuid(1)); // Check the first tenant. var kvc1 = mtc.GetCache(ToGuid(1)); Assert.IsNotNull(kvc1); Assert.AreEqual("1", kvc1[1]); Assert.AreEqual(1, mtc.Count); // Check the default policy for type. pa = CachePolicyManager.GetPolicies(); Assert.AreEqual(2, pa.Length); var p1 = pa.Where(x => x.Key == "MultiTenantCacheTest").SingleOrDefault(); Assert.IsNotNull(p1); Assert.IsInstanceOf(typeof(NoExpiryCachePolicy), p1.Value); // Check the second tenant. var kvc2 = mtc.GetCache(ToGuid(2)); Assert.IsNotNull(kvc2); Assert.AreEqual("X1", kvc2[1]); Assert.AreEqual(2, mtc.Count); // No new PolicyManager policies should be created. pa = CachePolicyManager.GetPolicies(); Assert.AreEqual(2, pa.Length); // Flush the cache - nothing should happen as they never expire. CachePolicyManager.Flush(); Assert.AreEqual(2, mtc.Count); // Remove a tenant. mtc.Remove(ToGuid(2)); Assert.IsTrue(mtc.Contains(ToGuid(1))); Assert.IsFalse(mtc.Contains(ToGuid(2))); Assert.AreEqual(1, mtc.Count); Assert.AreEqual(0, kvc2.Count); // Force flush the cache - should be removed. CachePolicyManager.ForceFlush(); Assert.IsFalse(mtc.Contains(ToGuid(1))); Assert.IsFalse(mtc.Contains(ToGuid(2))); Assert.AreEqual(0, mtc.Count); Assert.AreEqual(0, kvc1.Count); }
public void Concurrency() { CachePolicyManager.Reset(); ExecutionContext.Reset(false); int i = 0; var rdc = new ReferenceDataMultiTenantCache <TestRdCollection, TestRd>(() => { i++; return(GetData()); }); // Set an execution context. var tasks = new Task[10]; tasks[0] = Task.Run(() => Timer(0, GetGuid(08), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(08) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[1] = Task.Run(() => Timer(1, GetGuid(09), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(09) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[2] = Task.Run(() => Timer(2, GetGuid(1), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(1) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[3] = Task.Run(() => Timer(3, GetGuid(2), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(2) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[4] = Task.Run(() => Timer(4, GetGuid(08), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(08) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[5] = Task.Run(() => Timer(5, GetGuid(09), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(09) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[6] = Task.Run(() => Timer(6, GetGuid(1), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(1) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[7] = Task.Run(() => Timer(7, GetGuid(2), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(2) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[8] = Task.Run(() => Timer(8, GetGuid(08), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(08) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[9] = Task.Run(() => Timer(9, GetGuid(09), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(09) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); Task.WaitAll(tasks); TestContext.WriteLine("ROUND TWO"); tasks = new Task[10]; tasks[0] = Task.Run(() => Timer(0, GetGuid(08), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(08) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[1] = Task.Run(() => Timer(1, GetGuid(09), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(09) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[2] = Task.Run(() => Timer(2, GetGuid(1), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(1) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[3] = Task.Run(() => Timer(3, GetGuid(2), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(2) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[4] = Task.Run(() => Timer(4, GetGuid(08), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(08) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[5] = Task.Run(() => Timer(5, GetGuid(09), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(09) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[6] = Task.Run(() => Timer(6, GetGuid(1), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(1) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[7] = Task.Run(() => Timer(7, GetGuid(2), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(2) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[8] = Task.Run(() => Timer(8, GetGuid(08), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(08) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); tasks[9] = Task.Run(() => Timer(9, GetGuid(09), () => { ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(09) }); Assert.IsTrue(rdc.GetCollection().ActiveList.Count > 0); })); Task.WaitAll(tasks); }
public void Exercise() { CachePolicyManager.Reset(); ExecutionContext.Reset(false); int i = 0; var rdc = new ReferenceDataMultiTenantCache <TestRdCollection, TestRd>(() => { i++; return(GetData()); }); // Set an execution context. ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(1) }); // Nothing loaded. Assert.AreEqual(0, i); Assert.AreEqual(0, rdc.Count); Assert.IsTrue(rdc.IsExpired); // Now loaded. var c = rdc.GetCollection(); Assert.AreEqual(1, i); Assert.IsNotNull(c); Assert.AreEqual(2, c.ActiveList.Count); Assert.AreEqual(1, rdc.Count); Assert.IsFalse(rdc.IsExpired); // Same cached version. c = rdc.GetCollection(); Assert.AreEqual(1, i); Assert.IsNotNull(c); Assert.AreEqual(2, c.ActiveList.Count); Assert.AreEqual(1, rdc.Count); Assert.IsFalse(rdc.IsExpired); // Change the execution context. ExecutionContext.Reset(false); ExecutionContext.SetCurrent(new ExecutionContext { TenantId = GetGuid(2) }); // Now load new tenant. c = rdc.GetCollection(); Assert.AreEqual(2, i); Assert.IsNotNull(c); Assert.AreEqual(3, c.ActiveList.Count); Assert.AreEqual(2, rdc.Count); Assert.IsFalse(rdc.IsExpired); // Flush the cache. rdc.Flush(true); Assert.AreEqual(2, i); Assert.IsTrue(rdc.IsExpired); Assert.AreEqual(0, rdc.Count); // New collection cached. c = rdc.GetCollection(); Assert.AreEqual(3, i); Assert.IsNotNull(c); Assert.AreEqual(3, c.ActiveList.Count); Assert.AreEqual(1, rdc.Count); Assert.IsFalse(rdc.IsExpired); }
public void PolicyManager() { CachePolicyManager.Reset(); var i = 0; var mtc = new KeyValueCache <int, string>((key) => { i++; return(key.ToString()); }, "KeyValueCacheTest"); Assert.IsNotNull(mtc.PolicyKey); var policy = new DailyCachePolicy(); CachePolicyManager.Set(mtc.PolicyKey, policy); var policy2 = mtc.GetPolicy(); Assert.IsNotNull(policy2); Assert.AreSame(policy, policy2); var pa = CachePolicyManager.GetPolicies(); Assert.AreEqual(2, pa.Length); // Check the internal nocachepolicy. var p0 = pa.Where(x => x.Key.StartsWith("KeyValueCacheTest_")).SingleOrDefault(); Assert.IsNotNull(p0); Assert.IsInstanceOf(typeof(NoCachePolicy), p0.Value); // Check the default policy for type. var p1 = pa.Where(x => x.Key == "KeyValueCacheTest").SingleOrDefault(); Assert.IsNotNull(p1); Assert.IsInstanceOf(typeof(DailyCachePolicy), p1.Value); // Get (add) new item to cache. var s = mtc[1]; Assert.AreEqual("1", s); Assert.AreEqual(1, i); // No new globally managed policies should have been created. pa = CachePolicyManager.GetPolicies(); Assert.AreEqual(2, pa.Length); // Check policy for item is DailyCachePolicy but has its own instance. policy2 = mtc.GetPolicyByKey(1); Assert.IsNotNull(policy2); Assert.IsInstanceOf(typeof(DailyCachePolicy), policy2); Assert.AreNotSame(policy, policy2); // There should be no policy where item not found. Assert.IsNull(mtc.GetPolicyByKey(2)); // Flush cache where not expired. mtc.Flush(); s = mtc[1]; Assert.AreEqual("1", s); Assert.AreEqual(1, i); // Force flush; should reload cache after. CachePolicyManager.ForceFlush(); s = mtc[1]; Assert.AreEqual("1", s); Assert.AreEqual(2, i); }