Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    christiansent
    @christiansent
    Hi Sergiy. Been using NRules for a couple years. In one application recently moved from C# to loading from database. Worked well until now, have a problem that I am having trouble root causing. Here is exception trace. Exception has occurred: CLR/System.ArgumentException
    An exception of type 'System.ArgumentException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'Array may not be empty.'
    at System.DefaultBinder.SelectMethod(BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers)
    at NRules.RuleSharp.ParserContext.FindExtensionMethod(Type type, String methodName, Type[] argumentTypes)
    at NRules.RuleSharp.PrimaryExpressionBuilder.Method(String methodName, Type type, Expression instance, List1 argumentsList) at NRules.RuleSharp.PrimaryExpressionBuilder.Method(List1 argumentsList)
    at NRules.RuleSharp.ExpressionParser.VisitPrimary_expression(Primary_expressionContext context)
    at NRules.RuleSharp.Parser.RuleSharpParser.Primary_expressionContext.AcceptTResult
    at Antlr4.Runtime.Tree.AbstractParseTreeVisitor1.Visit(IParseTree tree) at NRules.RuleSharp.ExpressionParser.VisitUnary_expression(Unary_expressionContext context) at NRules.RuleSharp.Parser.RuleSharpParser.Unary_expressionContext.Accept[TResult](IParseTreeVisitor1 visitor)
    at Antlr4.Runtime.Tree.AbstractParseTreeVisitor1.Visit(IParseTree tree) at NRules.RuleSharp.ExpressionParser.VisitMultiplicative_expression(Multiplicative_expressionContext context) at NRules.RuleSharp.Parser.RuleSharpParser.Multiplicative_expressionContext.Accept[TResult](IParseTreeVisitor1 visitor)
    at Antlr4.Runtime.Tree.AbstractParseTreeVisitor1.Visit(IParseTree tree) at NRules.RuleSharp.ExpressionParser.VisitAdditive_expression(Additive_expressionContext context) at NRules.RuleSharp.Parser.RuleSharpParser.Additive_expressionContext.Accept[TResult](IParseTreeVisitor1 visitor)
    at Antlr4.Runtime.Tree.AbstractParseTreeVisitor1.VisitChildren(IRuleNode node) at NRules.RuleSharp.Parser.RuleSharpParserBaseVisitor1.VisitShift_expression(Shift_expressionContext context)
    at NRules.RuleSharp.Parser.RuleSharpParser.Shift_expressionContext.AcceptTResult
    at Antlr4.Runtime.Tree.AbstractParseTreeVisitor1.Visit(IParseTree tree) at NRules.RuleSharp.ExpressionParser.VisitRelational_expression(Relational_expressionContext context) at NRules.RuleSharp.Parser.RuleSharpParser.Relational_expressionContext.Accept[TResult](IParseTreeVisitor1 visitor)
    at Antlr4.Runtime.Tree.AbstractParseTreeVisitor1.Visit(IParseTree tree) at NRules.RuleSharp.ExpressionParser.VisitEquality_expression(Equality_expressionContext context) at NRules.RuleSharp.Parser.RuleSharpParser.Equality_expressionContext.Accept[TResult](IParseTreeVisitor1 visitor)
    at Antlr4.Runtime.Tree.AbstractParseTreeVisitor1.Visit(IParseTree tree) at NRules.RuleSharp.ExpressionParser.VisitAnd_expression(And_expressionContext context) at NRules.RuleSharp.Parser.RuleSharpParser.And_expressionContext.Accept[TResult](IParseTreeVisitor1 visitor)
    at Antlr4.Runtime.Tree.AbstractParseTreeVisitor1.Visit(IParseTree tree) at NRules.RuleSharp.ExpressionParser.VisitExclusive_or_expression(Exclusive_or_expressionContext context) at NRules.RuleSharp.Parser.RuleSharpParser.Exclusive_or_expressionContext.Accept[TResult](IParseTreeVisitor1 visitor)
    at Antlr4.Runtime.Tree.AbstractParseTreeVisitor1.Visit(IParseTree tree) at NRules.RuleSharp.ExpressionParser.VisitInclusive_or_expression(Inclusive_or_expressionContext context) at NRules.RuleSharp.Parser.RuleSharpParser.Inclusive_or_expressionContext.Accept[TResult](IParseTreeVisitor1 visitor)
    at Antlr4.Runtime.Tree.AbstractParseTreeVisitor1.Visit(IParseTree tree) at NRules.RuleSharp.ExpressionParser.VisitConditional_and_expression(Conditional_and_expressionContext context) at NRules.RuleSharp.Parser.RuleSharpParser.Conditional_and_expressionContext.Accept[TResult](IParseTreeVisitor1 visitor)
    2 replies
    Error happens when repository.LoadText is called
    christiansent
    @christiansent
    I figured it out, was error in function call on Fact
    1 reply
    christiansent
    @christiansent
    I had a function on the Fact object (Attribute_BASE with derived classes) with two parameters. The second was optional. I think that not supplying the optional second caused a problem. The problem disappeared when I split the function into two: 1) one parameter, 2) two parameters (second required, not optional). Hope this helps
    John Coleman
    @JohnSColeman
    Hi, what is the rul equivalent of this drl:
    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
    4 replies
    Sergiy Nikolayev
    @snikolayev
    PSA - moving forward, please ask questions related to NRules.RuleSharp, rul files, NRules.Language here: https://gitter.im/NRules/NRules.Language
    And keep asking questions about NRules fluent C# DSL and NRules runtime here in this forum
    1 reply
    karthik sundar
    @karthikn92-sundar
    Is there a way to dynamically change the right hand side values.
    For eg. When()
    .Query(() => currentCartItem, p => p
    .Match<ShoppingCartItem>(
    c => (c.Status != null && (c.Status.ToUpper() == "OPEN" || c.Status.ToUpper() == "P" || c.Status.ToUpper() == "NULL")) && c.NumberOfUniqueParts > '25'
    )
    .Collect()
    .Where(c => c.Any()));
                Then()
                    .Do(ctx => SendEmailNotification(currentCartItem));
    1 reply
    i want to change the NumberOfUniqueParts value from 25 to 50
    is this possible ?
    Entropy0
    @Entropy0

    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();
            }
        }
    }
    3 replies
    Sergiy Nikolayev
    @snikolayev
    @Entropy0 read my general response in the thread. Here is an example of a memory profile with a simple dictionary where the memory footprint is higher even after running GC
    Dictionary-Footprint.png
    NRules uses rete algorithm, so there are some bookkeeping structures to store partial matches within the Rete graph, so the memory utilization is larger than just a dictionary. But the profiler picture is generally the same - the objects are collected, but memory not fully reclaimed by the runtime
    Sergiy Nikolayev
    @snikolayev
    Here is the same memory profiler view with your sample:
    Rete-Footprint.png
    And diffing the snapshots shows that all objects related to the 1mil facts you inserted/retracted have not survived:
    Rete-Snapshot-Compare.png
    Entropy0
    @Entropy0
    @snikolayev Okay, so it's simply an issue with GC but the memory would still be available if needed? I think I can live with that.
    Thanks for the detailed and fast response :-)
    Sergiy Nikolayev
    @snikolayev
    @Entropy0 I wouldn’t characterize it as an “issue” with GC, but just as how it works. It collects the objects, it just doesn’t immediately return the memory to the OS. If there was memory pressure in the system I’m sure it would shrink the working set. And yes, if you allocate more objects that memory is available for them.
    wangadeketan
    @wangadeketan

    @snikolayev

    @wangadeketan definitely releasing new version this year. Hopefully much sooner than the EOY

    Any update ?

    4 replies
    Sergiy Nikolayev
    @snikolayev
    NRules 0.9.1 is out! See release notes for details: https://github.com/NRules/NRules/releases/v0.9.1
    larrybehaviorlanguage
    @larrybehaviorlanguage
    @snikolayev Congratulations on the release! Just a heads up that we happened to come across this issue purely by accident. I managed to repro it in a unit test in the NRules project, which I included in the ticket: NRules/NRules#246.
    When we first found it, our Or clauses were spread across multiple Or blocks deeply nested within Ands and Ors, but it turns out that I was able to repro the issue without any nesting at all.
    Sergiy Nikolayev
    @snikolayev
    Hi @larrybehaviorlanguage - thanks for a repro scenario - I can see the behavior you are describing in the repro test you created. I'm looking into this. I'll let you know what I find.
    larrybehaviorlanguage
    @larrybehaviorlanguage
    @snikolayev Great, thank you. The last point regarding “ Adding a call to a boolean-returning method at the end of the second clause's final test” threw me because I was adding methods like this in for debug logging and they suppressed the problem!
    Sergiy Nikolayev
    @snikolayev
    @larrybehaviorlanguage it appears this bug has been there for a while (I was worried that 0.9.1 introduced it). The issue is with expression comparison for node sharing, where you have two facts of the same type, and the expressions are literally identical, other than joining to different instances of the same fact. The expression comparison fails to distinguish them, and erroneously shares the nodes believing the expressions 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.
    larrybehaviorlanguage
    @larrybehaviorlanguage
    @snikolayev Gotcha. Glad you're able to track it down. Hope the fix isn't too bad.
    Sergiy Nikolayev
    @snikolayev
    @larrybehaviorlanguage FYI I fixed it in develop branch
    larrybehaviorlanguage
    @larrybehaviorlanguage
    @snikolayev That fixed our issue, thanks very much!
    Suman S
    @sumankpm_twitter
    Hi, Since i have license issue's with Visual studio at present. I'm trying out NRules (Rule engine) sample in Visual studio code. How do install the NRules package in Termial ???
    wangadeketan
    @wangadeketan
    Hi @snikolayev ,
    I want to implement one simple rule which will check logger level according to their environment like development, production.
    How can I achieve this using Nrules.
    Sergiy Nikolayev
    @snikolayev
    @wangadeketan it sounds a bit odd to me to look at log level of environment name in business rules. In any case, one option is to insert these concepts as facts into the session.
    wangadeketan
    @wangadeketan
    @snikolayev, Thanks for response.
    I think I have not properly mention my question.
    I am writing one rule which will check log level according to their environment like for development log level is debug and for production log level must be Error.
    I need you guidance how can I can I write this type of rule because their is no database model so how can I execute match and when condition.
    Sergiy Nikolayev
    @snikolayev
    @wangadeketan I'll just say that IMO it seems wrong to do something in the business rules based on what log level is currently enabled. With that caveat, I obviously don't know your circumstances, so if you must do it, here is an example with log4net:
        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";
            }
        }
    wangadeketan
    @wangadeketan
    @snikolayev Thanks for quick response
    Huzaif Abdul-Sattar
    @zaifworks
    First, Thanks for building and maintaining a great product.
    Huzaif Abdul-Sattar
    @zaifworks

    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?

    3 replies
    Sergiy Nikolayev
    @snikolayev
    The next release of NRules will no longer target .net framework 4.5 or .net standard 1.0. It will target .net standard 2.0 and .net standard 2.1. Given .net standard version compatibility chart this will allow NRules to be used from applications targeting .net framework 4.6.1+, .net core 2.0+ and .net 5. I'm still debating whether to target .net 5 directly - it does not seem to provide any immediate benefit.
    I just wanted to let everyone know ahead of time. Please let me know if there are any concerns with dropping the support of the lower framework versions.