import model.LineItem;
import model.Brand;
import model.Market;
import model.Seller;
global java.util.List coupons;
rule "Rule 1"
when
exists LineItem(category == "PC", market in (Market.MARKETPLACE1), brand in (Brand.ACER))
then
coupons.add("#PC0001");
end
Then()
.Do(ctx => SendEmailNotification(currentCartItem));
Is there a way to properly remove a fact from the sessions memory once inserted?
Simply calling Remove
/ TryRemove
doesn't actually free any memory...
Minimized example of what I am currently trying to do:
using System;
using NRules;
using NRules.Fluent;
using NRules.Fluent.Dsl;
namespace Playground
{
class Fact
{
public int data { get; set; }
}
public class TestRule : Rule
{
public override void Define()
{
Fact fact = null;
When()
.Match<Fact>(() => fact);
Then()
.Do(ctx => Console.WriteLine("fact " + fact.data));
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("press any key to start...");
Console.ReadKey();
var repository = new RuleRepository();
repository.Load(x => x.From(typeof(Program).Assembly));
var factory = repository.Compile();
var session = factory.CreateSession();
Console.WriteLine("inserting facts...\n");
for (int i = 0; i < 1000000; ++i)
{
session.Insert(new Fact { data = i });
}
// memory usage has now grown to ~800 MB
Console.WriteLine("press any key to retract facts...");
Console.ReadKey();
foreach (var fact in session.Query<Fact>())
{
if (!session.TryRetract(fact))
{
Console.WriteLine("retracting " + fact.data + " failed"); // no output -> no errors
}
}
foreach (var fact in session.Query<Fact>())
{
Console.WriteLine("still in memory: " + fact.data + ")"); // no output -> no facts in session
}
// memory usage hasn't dropped down again
Console.WriteLine("\nPress any key to continue...");
Console.ReadKey();
}
}
}
rf => rf.ReferenceB == myNameFact
and rf => rf.ReferenceB == otherNameFact
are the same. The reason the issue goes away as soon as you change or add expressions, is that the opportunity for node sharing goes away. I'm working on fixing it.
public class LogLevelRule : Rule
{
public static ILog Log = LogManager.GetLogger("MyLogger");
public override void Define()
{
string logLevel = default;
When()
.Query(() => logLevel, q => q
.From(() => GetCurrentLogLevel(Log)));
Then()
.Do(x => Console.WriteLine($"Logging at {logLevel} with {Log.Logger.Name}"));
}
private string GetCurrentLogLevel(ILog logger)
{
if(logger.IsDebugEnabled)
return "Debug";
if(logger.IsInfoEnabled)
return "Info";
if(logger.IsWarnEnabled)
return "Warn";
if(logger.IsErrorEnabled)
return "Error";
if(logger.IsFatalEnabled)
return "Fatal";
return "None";
}
}
We are planning on using NRules as an engine in a multi-tenant environment. As such, we would like to keep the rules repo (and the associated factories) separated. In the same process.
We would setup a dictionary of tenants and their associated rules repo/factory. When a fact is generated in the app, it would pass it to the process. We will search the dictionary for the tenant. We would then use the factory returned for the tenant to setup a session and process the fact.
Do you guys think there are any problems with this design?
We have a few hundred rules and we are logging RuleFired, RuleFiring, and others. We are logging everything and it is overwhelming, with thousands of events being captured. I am trying to see if there is a way that I could write some logic that captures the rules that fired for each session, captures the rule/rule info in an object, and after the last rule for that session runs can send that log.
Is there a way to tell when the rules sessions has started and is complete and will no longer be called until the next session?
Hi all, just getting started with NRules, and we're planning on using it as a constraint mechanism; basically a bunch of rules accept the same input, and I want to get a true/false that all succeeded, or find out that some rule failed. So, it's less about having side effects executed by each rule, but using the rules as a gatekeeper for the next logic I want to execute.
A naive approach would be to use Match to find data which does not fit the rule, and use Do to throw an exception. When I catch the exception, I can log it and return 'false'.
Obviously this isn't the optimal use of exceptions for logic, and I wanted to ask if there's a better approach I'm missing? I was looking for a way to pass back some state from each rule, and check this via the session after it had fired. Is that possible?