Uploaded image for project: 'JBRULES'
  1. JBRULES
  2. JBRULES-1392

Rules behave incorrectly (randomly) in multi-threaded environment

    XMLWordPrintable

    Details

      Description

      Rules behave seemingly indeterminately when sessions are created from the same RuleBase and executed in multiple threads. The problem is a bit difficult to reproduce. The following code demonstrates the behavior in my environment (single processor PowerBook), but not on every try. I've had up to 5 consecutive executions not exhibit the problem before the failure was exhibited, so you may need to run the class a number of times to see the problem. Also, I periodically get OutOfMemoryErrors when using the default heap size (64m). I've had better success with -Xmx256m. That, by the way, is suspiciously coincidental to the random nature of the incorrect rule firing problem.

      I've experienced this behavior in my application, and it manifests by rules firing from time to time that shouldn't have fired. I can't see a pattern to the rules that fire inappropriately, and there absolutely were not facts asserted that would support the firing of the rule.

      Synchronizing the calls to insert, fireAllRules, and dispose on the session object seems to get rid of the problem, giving further evidence to the guess that it's a multithreading bug.

      Please, please, please find a solution to this problem. This will be a serious scalability problem for my application. I'm more than happy to help however I can. I've stepped through Drools code before and found solutions, but I really don't know where to go with this one.

      Following is the code (self-contained class with main method) that I've used to demonstrate the problem.

      Thank you!

      package sample;

      import java.io.StringReader;
      import java.util.ArrayList;

      import org.drools.RuleBase;
      import org.drools.RuleBaseConfiguration;
      import org.drools.RuleBaseFactory;
      import org.drools.StatefulSession;
      import org.drools.compiler.PackageBuilder;
      import org.drools.compiler.PackageBuilderConfiguration;

      public class MultithreadedRuleBaseProblem {

      public static void main(String[] args) throws Exception {

      final PackageBuilderConfiguration packageBuilderConfiguration =
      new PackageBuilderConfiguration();
      final PackageBuilder packageBuilder = new PackageBuilder(packageBuilderConfiguration);

      packageBuilder.addPackageFromDrl(new StringReader("\n"
      + "package sample\n"
      + "\n"
      + "import java.lang.Integer;\n"
      + "global java.util.ArrayList shouldFireList;\n"
      + "global java.util.ArrayList shouldNotFireList;\n"
      + "\n"
      + "rule should_fire\n"
      + " when\n"
      + " $e : Integer(intValue == -1)\n"
      + " $f : Integer(intValue > $e)\n"
      + " then \n"
      + " shouldFireList.add($f);\n"
      + "end \n"
      + "\n"
      + "rule should_not_fire\n"
      + " when\n"
      + " $f : String()\n"
      + " then \n"
      + " shouldNotFireList.add($f);\n"
      + "end \n"));

      final RuleBaseConfiguration ruleBaseConfiguration = new RuleBaseConfiguration();
      final RuleBase ruleBase = RuleBaseFactory.newRuleBase(ruleBaseConfiguration);
      ruleBase.addPackage(packageBuilder.getPackage());

      final Exception[] exception =

      { null }

      ;
      final Thread t[] = new Thread[50];
      for (int i = 0; i < t.length; i++) {
      final int count = i;
      t[i] = new Thread(new Runnable() {

      public void run() {
      try {
      System.out.println("Start " + count);
      final int iterations = count * 15 + 3000;
      final ArrayList shouldFireList = new ArrayList();
      final ArrayList shouldNotFireList = new ArrayList();
      final StatefulSession session2 = ruleBase.newStatefulSession();
      session2.setGlobal("shouldFireList", shouldFireList);
      session2.setGlobal("shouldNotFireList", shouldNotFireList);
      session2.insert(new Integer(- 1));
      for (int k = 0; k < iterations; k++)

      { session2.insert(new Integer(k)); }

      session2.insert("foo");
      System.out.println("Fire " + count);
      session2.fireAllRules();
      session2.dispose();
      if (shouldFireList.size() != iterations)

      { System.out.println("Thread " + count + " shouldFireList.size(): expected " + iterations + " was " + shouldFireList.size() + "\n!!!!! Thread " + count + " rule didn't fire as many times as it should have!!!!!!!!!!!!!!!!!!"); }

      } catch (Exception e)

      { e.printStackTrace(); exception[0] = e; }

      System.out.println("Thread " + count + " done");
      }
      });
      t[i].start();
      }
      for (int i = 0; i < t.length; i++)

      { t[i].join(); }

      System.out.println("done");
      }
      }

        Gliffy Diagrams

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  tirelli Edson Tirelli
                  Reporter:
                  bstiles Brian Stiles
                • Votes:
                  1 Vote for this issue
                  Watchers:
                  5 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved: