Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions src/RulesEngine/Actions/EvaluateRuleAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,28 @@ internal async override ValueTask<ActionRuleResult> ExecuteAndReturnResultAsync(
List<RuleResultTree> resultList = null;
if (includeRuleResults)
{
resultList = new List<RuleResultTree>(output?.Results ?? new List<RuleResultTree>() { });
resultList.AddRange(innerResult.Results);
// Avoid exponential copying by only including the immediate results from this execution
// The chained rule results are already included in output?.Results
resultList = new List<RuleResultTree>();

// Add the chained rule results (from the EvaluateRule action execution)
if (output?.Results != null)
{
resultList.AddRange(output.Results);
}

// Add the parent rule that triggered this chain (but avoid duplicating it)
if (innerResult.Results != null)
{
foreach (var result in innerResult.Results)
{
// Only add if it's not already in the output results to avoid duplication
if (output?.Results == null || !output.Results.Any(r => ReferenceEquals(r, result)))
{
resultList.Add(result);
}
}
}
}
return new ActionRuleResult {
Output = output?.Output,
Expand Down
26 changes: 24 additions & 2 deletions src/RulesEngine/RulesEngine.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using FluentValidation;
Expand Down Expand Up @@ -128,11 +128,33 @@ private async ValueTask ExecuteActionAsync(IEnumerable<RuleResultTree> ruleResul

public async ValueTask<ActionRuleResult> ExecuteActionWorkflowAsync(string workflowName, string ruleName, RuleParameter[] ruleParameters)
{
var compiledRule = CompileRule(workflowName, ruleName, ruleParameters);
var compiledRule = GetCompiledRule(workflowName, ruleName, ruleParameters);
var resultTree = compiledRule(ruleParameters);
return await ExecuteActionForRuleResult(resultTree, true);
}

private RuleFunc<RuleResultTree> GetCompiledRule(string workflowName, string ruleName, RuleParameter[] ruleParameters)
{
// Ensure the workflow is registered and rules are compiled
if (!RegisterRule(workflowName, ruleParameters))
{
throw new ArgumentException($"Rule config file is not present for the {workflowName} workflow");
}

// Get the compiled rule from cache
var compiledRulesCacheKey = GetCompiledRulesKey(workflowName, ruleParameters);
var compiledRules = _rulesCache.GetCompiledRules(compiledRulesCacheKey);

if (compiledRules?.TryGetValue(ruleName, out var compiledRule) == true)
{
return compiledRule;
}

// Fallback to individual compilation if not found in cache
// This should rarely happen, but provides safety
return CompileRule(workflowName, ruleName, ruleParameters);
}

private async ValueTask<ActionRuleResult> ExecuteActionForRuleResult(RuleResultTree resultTree, bool includeRuleResults = false)
{
var ruleActions = resultTree?.Rule?.Actions;
Expand Down