Uploaded image for project: 'Drools'
  1. Drools
  2. DROOLS-309

Multiple threads working with traits against same knowledge base hangs

    XMLWordPrintable

Details

    • Quality Risk
    • Resolution: Done
    • Major
    • 5.5.1.Final, 6.0.0.Final
    • 5.5.0.Final
    • None
    • None

    Description

      In our web system, we are creating new StatefulKnowledgeSession per user session and executing a set of rules containing trait donning. This starts to hang (seemingly indefinitely) with following type of stack trace (usually initiated from insert/update):

      java.lang.Thread.State: RUNNABLE
      at org.drools.core.util.TripleStore.getAll(TripleStore.java:188)
      at org.drools.factmodel.traits.TripleBasedStruct.getTriplesForSubject(TripleBasedStruct.java:165)
      at org.drools.factmodel.traits.ThingorgdroolsfactmodeltraitsTraitSession$ItemWrapperProxyWrapper.hashCode(Unknown Source)
      at org.drools.factmodel.traits.TraitProxy.hashCode(TraitProxy.java:110)
      at org.drools.factmodel.traits.ThingorgdroolsfactmodeltraitsTraitSession$ItemWrapperProxy.hashCode(Unknown Source)
      at org.drools.common.DefaultFactHandle.<init>(DefaultFactHandle.java:110)
      at org.drools.common.DefaultFactHandle.<init>(DefaultFactHandle.java:98)
      at org.drools.common.TraitFactHandle.<init>(TraitFactHandle.java:26)
      at org.drools.reteoo.ReteooFactHandleFactory.newFactHandle(ReteooFactHandleFactory.java:80)
      at org.drools.common.AbstractFactHandleFactory.newFactHandle(AbstractFactHandleFactory.java:68)
      at org.drools.common.AbstractFactHandleFactory.newFactHandle(AbstractFactHandleFactory.java:53)
      at org.drools.common.NamedEntryPoint.createHandle(NamedEntryPoint.java:765)
      at org.drools.common.NamedEntryPoint.insert(NamedEntryPoint.java:301)
      at org.drools.common.AbstractWorkingMemory.insert(AbstractWorkingMemory.java:903)

      Here is a unit test for org.drools.factmodel.traits.TraitTest. It's not perfect because it will spawn thread that might never die and may need thread/iteration count increased to fail consistently, but capturing a stack trace a few seconds in should show all threads in "getAll()":

          @Traitable
          public static class Item {
          	private String id;
      
          	public String getId() {
          		return id;
          	}
      
          	public void setId(String id) {
          		this.id = id;
          	}
          }
      
          public static class TraitRulesThread implements Runnable {
          	int threadIndex;
          	int numRepetitions;
          	StatefulKnowledgeSession ksession;
      
          	public TraitRulesThread(int threadIndex, int numRepetitions, final StatefulKnowledgeSession ksession) {
          		this.threadIndex = threadIndex;
          		this.numRepetitions = numRepetitions;
          		this.ksession = ksession;
          	}
          	public void run() {
          		for (int repetitionIndex = 0; repetitionIndex < numRepetitions; repetitionIndex++) {
          			final Item i = new Item();
          			i.setId(String.format("testId_%d%d", threadIndex, repetitionIndex));
          			ksession.insert(i);
          			ksession.fireAllRules();
          		}
          	}
          }
      
          @Test
          public void testMultithreadingTraits() throws InterruptedException {
          	final String s1 = "package test;\n" +
          	"import org.drools.factmodel.traits.TraitTest.Item;\n" +
          	"declare Item end\n" +
          	"declare trait ItemStyle\n" +
          	"	id: String\n" +
          	"	adjustable: boolean\n" +
          	"end\n" +
          	"rule \"Don ItemStyle\"\n" +
          	"	no-loop true\n" +
          	"	when\n" +
          	"		$p : Item ()\n" +
          	"		not ItemStyle ( id == $p.id )\n" +
          	"	then\n" +
          	"		don($p, ItemStyle.class);\n" +
          	"end\n" +
          	"rule \"Item Style - Adjustable\"" +
          	"	no-loop true" +
          	"	when" +
          	"		$style : ItemStyle ( !adjustable )" +
          	"		Item (" +
          	"			id == $style.id " +
          	"		)" +
          	"	then" +
          	"		modify($style) {" +
          	"			setAdjustable(true)" +
          	"		};" +
          	"end";
          	final KnowledgeBase kbase = getKnowledgeBaseFromString(s1);
      
          	// might need to tweak these numbers.  often works with 7-10,100,60, but often fails 15-20,100,60
          	int MAX_THREADS = 20;
          	int MAX_REPETITIONS = 100;
          	int MAX_WAIT_SECONDS = 60;
      
          	final ExecutorService executorService = Executors.newFixedThreadPool(MAX_THREADS);
          	for (int threadIndex = 0; threadIndex < MAX_THREADS; threadIndex++) {
          		executorService.execute(new TraitRulesThread(threadIndex, MAX_REPETITIONS, kbase.newStatefulKnowledgeSession()));
          	}
      
          	executorService.shutdown();
          	executorService.awaitTermination(MAX_WAIT_SECONDS, TimeUnit.SECONDS);
          	final List<Runnable> queuedTasks = executorService.shutdownNow();
      
          	assertEquals(0, queuedTasks.size());
          	assertEquals(true, executorService.isTerminated());
          }
      

      Attachments

        Activity

          People

            mfusco@redhat.com Mario Fusco
            james.myers James Myers (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: