diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f10fcee..7f9e178f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All notable changes to this project will be documented in this file. +## [3.0.2] +- Fixed LocalParams cache not getting cleaned up when RemoveWorkflow and ClearWorkflows are called + ## [3.0.1] - Moved ActionResult and ActionRuleResult under RulesEngine.Models namespace diff --git a/src/RulesEngine/RulesEngine.cs b/src/RulesEngine/RulesEngine.cs index aa243f0c..33f9099e 100644 --- a/src/RulesEngine/RulesEngine.cs +++ b/src/RulesEngine/RulesEngine.cs @@ -32,7 +32,7 @@ public class RulesEngine : IRulesEngine private readonly ILogger _logger; private readonly ReSettings _reSettings; private readonly RulesCache _rulesCache = new RulesCache(); - private readonly MemoryCache _compiledParamsCache = new MemoryCache(new MemoryCacheOptions()); + private MemoryCache _compiledParamsCache = new MemoryCache(new MemoryCacheOptions()); private readonly ParamCompiler _ruleParamCompiler; private readonly RuleExpressionParser _ruleExpressionParser; private readonly RuleCompiler _ruleCompiler; @@ -179,6 +179,7 @@ public void AddWorkflow(params WorkflowRules[] workflowRules) public void ClearWorkflows() { _rulesCache.Clear(); + ClearCompiledParamCache(); } /// @@ -191,6 +192,7 @@ public void RemoveWorkflow(params string[] workflowNames) { _rulesCache.Remove(workflowName); } + ClearCompiledParamCache(); } /// @@ -404,6 +406,16 @@ private static string UpdateErrorMessage(string errorMessage, IDictionary + /// Clears all compiledParams + /// + private void ClearCompiledParamCache() + { + _compiledParamsCache.Dispose(); + _compiledParamsCache = new MemoryCache(new MemoryCacheOptions()); + } + #endregion } } diff --git a/src/RulesEngine/RulesEngine.csproj b/src/RulesEngine/RulesEngine.csproj index ef415256..a90d4287 100644 --- a/src/RulesEngine/RulesEngine.csproj +++ b/src/RulesEngine/RulesEngine.csproj @@ -2,13 +2,13 @@ netstandard2.0 - 3.0.1 + 3.0.2 Copyright (c) Microsoft Corporation. LICENSE https://github.com/microsoft/RulesEngine Abbas Cyclewala, Dishant Munjal, Yogesh Prajapati Rules Engine is a package for abstracting business logic/rules/policies out of the system. This works in a very simple way by giving you an ability to put your rules in a store outside the core logic of the system thus ensuring that any change in rules doesn't affect the core system. - https://github.com/microsoft/RulesEngine/blob/master/CHANGELOG.md + https://github.com/microsoft/RulesEngine/blob/main/CHANGELOG.md BRE, Rules Engine, Abstraction diff --git a/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs b/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs index 44a59fc3..165850c6 100644 --- a/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs +++ b/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs @@ -231,7 +231,6 @@ public async Task ClearWorkflow_RemovesAllWorkflow(string ruleFileName) await Assert.ThrowsAsync(async () => await re.ExecuteAllRulesAsync("inputWorkflowReference", input1, input2, input3)); } - [Theory] [InlineData("rules1.json")] [InlineData("rules2.json")] @@ -416,6 +415,75 @@ public async Task ExecuteRule_MissingMethodInExpression_DefaultParameter(string Assert.IsType>(result); Assert.All(result, c => Assert.False(c.IsSuccess)); } + + [Fact] + public async Task RemoveWorkFlow_ShouldRemoveAllCompiledCache() + { + var workflow = new WorkflowRules { + WorkflowName = "Test", + Rules = new Rule[]{ + new Rule { + RuleName = "RuleWithLocalParam", + LocalParams = new LocalParam[] { + new LocalParam { + Name = "lp1", + Expression = "true" + } + }, + RuleExpressionType = RuleExpressionType.LambdaExpression, + Expression = "lp1 == true" + } + } + }; + + var re = new RulesEngine(); + re.AddWorkflow(workflow); + + var result1 = await re.ExecuteAllRulesAsync("Test","hello"); + Assert.True(result1.All(c => c.IsSuccess)); + + re.RemoveWorkflow("Test"); + workflow.Rules.First().LocalParams.First().Expression = "false"; + + re.AddWorkflow(workflow); + var result2 = await re.ExecuteAllRulesAsync("Test", "hello"); + Assert.True(result2.All(c => c.IsSuccess == false)); + } + + [Fact] + public async Task ClearWorkFlow_ShouldRemoveAllCompiledCache() + { + var workflow = new WorkflowRules { + WorkflowName = "Test", + Rules = new Rule[]{ + new Rule { + RuleName = "RuleWithLocalParam", + LocalParams = new LocalParam[] { + new LocalParam { + Name = "lp1", + Expression = "true" + } + }, + RuleExpressionType = RuleExpressionType.LambdaExpression, + Expression = "lp1 == true" + } + } + }; + + var re = new RulesEngine(); + re.AddWorkflow(workflow); + + var result1 = await re.ExecuteAllRulesAsync("Test", "hello"); + Assert.True(result1.All(c => c.IsSuccess)); + + re.ClearWorkflows(); + workflow.Rules.First().LocalParams.First().Expression = "false"; + + re.AddWorkflow(workflow); + var result2 = await re.ExecuteAllRulesAsync("Test", "hello"); + Assert.True(result2.All(c => c.IsSuccess == false)); + } + private RulesEngine CreateRulesEngine(WorkflowRules workflow) { var json = JsonConvert.SerializeObject(workflow);