jboss-gpe / processFlowProvision

Other
11 stars 7 forks source link

Clean facts from KSession when returning session to session-pool. #24

Closed DuncanDoyle closed 10 years ago

DuncanDoyle commented 10 years ago

Facts inserted into a session (e.g. kcontext.getKnowledgeRuntime().insert(new MyFact()), which might be used by RuleNodes, don't get cleaned after the process has completed. This implies that these facts will still be available in the session when the session is reused by a new process. This can cause serious issues in process (especially rule) execution, like crosstalk between process instances.

Although one might say that it's the responsibility of the process to clean the facts from the session, this requires (deep) knowledge of the implementation of jBPM (and PFP), which we try to hide.

A possible solution is to clean the KSession by retracting all the facts from the KSession on process completion.

DuncanDoyle commented 10 years ago

Some sample code that shows how to do this. I've implemented this as a separate ProcessEventListener for now, which I configure via session.template. However, this should be part of the SessionPerPInstanceBean class IMHO (haven't added it to that class yet as my PFP workspace is kind of a mess atm):

@Override
public void afterProcessCompleted(ProcessCompletedEvent event) {
    KnowledgeRuntime kruntime = event.getKnowledgeRuntime();
    if (kruntime instanceof StatefulKnowledgeSession) {
        StatefulKnowledgeSession ksession = (StatefulKnowledgeSession) kruntime;
        LOGGER.debug("Cleaning StatefulKnowledgeSession '" + ksession.getId() + "'. Removing all facts from the session's WorkingMemory.");
        Collection<FactHandle> factHandles = ksession.getFactHandles();
        for (FactHandle nextFactHandle: factHandles) {
            ksession.retract(nextFactHandle);
        }
    }
}
DuncanDoyle commented 10 years ago

Slightly updated version does not require a cast from KnowledgeRuntime to StatefulKnowledgeSession and also cleans globals:

@Override
public void afterProcessCompleted(ProcessCompletedEvent event) {
    KnowledgeRuntime kruntime = event.getKnowledgeRuntime();

    //Retract all the facts from the knowledge runtime.
    LOGGER.debug("Cleaning KnowledgeRuntime. Removing all facts from the runtime's WorkingMemory.");
    Collection<FactHandle> factHandles = kruntime.getFactHandles();
    for (FactHandle nextFactHandle : factHandles) {
        kruntime.retract(nextFactHandle);
    }
    // Reset globals in the knowledge runtime.
    LOGGER.debug("Cleaning KnowledgeRuntime. Resetting all global references.");
    MapGlobalResolver globals = (MapGlobalResolver) kruntime.getGlobals();
    Entry<Object, Object>[] entries = globals.getGlobals();
    for (Entry<Object, Object> nextEntry : entries) {
        nextEntry.setValue(null);
    }
}
jboss-gpe commented 10 years ago

Thanks Duncan. Just pushed a commit that includes your last recommendation in the body of the afterProcessCompleted function.