[rules-users] Dynamic updates of stateful sessions
Esteban Aliverti
esteban.aliverti at gmail.com
Tue Apr 19 07:57:27 EDT 2011
There is no need to update your kbase in the listener. The agent will apply
all the changes to the provided kbase. If you already have a stateful
ksession from that kbase, then the changes in the kbase should be
reflected immediately.
Could you please post the log output of the kagent?
Best Regards,
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Esteban Aliverti
- Developer @ http://www.plugtree.com
- Blog @ http://ilesteban.wordpress.com
On Tue, Apr 19, 2011 at 4:24 AM, Mattias Avelin
<mattias.avelin at netlight.se>wrote:
> Hi!
>
> Yes, I have already implemented a KnowledgeAgentEventListener acts on
> KnowledgeBaseUpdatedEvent and ResourceCompilationFailedEvent. I use this to
> update my knowledgebase reference in my class that wraps the KnowledgeBase
> and KnowledgeAgent. Below is the code for this class
> ("DynamicDecisionService"). I suspect that I have missed something vital
> since I'm actually not getting my knowledgebase to update itself either but
> I "do it myself" in the listener when I receive a KnowledgeBaseUpdatedEvent.
>
> Here is the code that handles the KnowledgeAgent and KnowledgeBase (I have
> stripped out some labels and comments since this belongs to the client).
>
> Best regards
>
> Mattias Avelin
>
> package com.x.service;
>
> import java.util.ArrayList;
> import org.apache.log4j.Logger;
> import org.drools.KnowledgeBase;
> import org.drools.KnowledgeBaseConfiguration;
> import org.drools.KnowledgeBaseFactory;
> import org.drools.agent.KnowledgeAgent;
> import org.drools.agent.KnowledgeAgentConfiguration;
> import org.drools.agent.KnowledgeAgentFactory;
> import org.drools.builder.KnowledgeBuilderError;
> import org.drools.builder.KnowledgeBuilderErrors;
> import org.drools.conf.EventProcessingOption;
> import org.drools.event.knowledgeagent.KnowledgeBaseUpdatedEvent;
> import org.drools.event.knowledgeagent.ResourceCompilationFailedEvent;
> import org.drools.event.rule.DefaultKnowledgeAgentEventListener;
> import org.drools.io.ResourceChangeScannerConfiguration;
> import org.drools.io.ResourceFactory;
>
> /**
> * {@inheritDoc}
> * <p>
> * This implementation of DecisionService updates the knowledgebase
> dynamically
> * when the underlying rules (drl-files) are updated. Therefore each call
> to the
> * createSession() method will return a session based on the most resent
> version
> * of the rules (allowing for some lag due to the intervals of the
> * resource scanner).
> * </p>
> * <p>
> * For statefull sessions the session needs to be updated "manually" when
> the
> * KnowledgeBase has been updated.
> * </P>
> * @author Mattias Avelin - mattias.avelin at netlight.se
> */
> public class DynamicDecisionService implements DecisionService
> {
> private static Logger LOG =
> Logger.getLogger(DynamicDecisionService.class);
>
> // Repository of all the application's knowledge definitions
> private KnowledgeBase kBase;
> // The agent that monitores the rule files (resources) for changes
> private KnowledgeAgent kAgent;
> // Decision service type
> private DecisionSessionType type;
> // When the current knowledgebase was created
> private long kbaseLastUpdated;
>
> /**
> * Create a DynamicDecisionService using a ChangeSet.
> *
> * @param changeSet - The ChangeSet referencing the rule-files to use
> * for this service. Expects a classpath reference
> *
> * @throws IllegalArgumentException if changeSet is not a valid
> ChangeSet.
> */
> public DynamicDecisionService(
> String changeSet,
> DecisionSessionType type)
> {
> this.kBase = createKnowledgeBase(type);
> // the method could reference kBase itself but I thought it
> // more more "clear" if I actually supply it in the method
> invocation
> this.kAgent = createKnowledgeAgent(changeSet, this.kBase);
> // This should not be neccesary according to all sources I've found
> // but without re-assigning the reference it doesn't work!?!?
> this.kBase = kAgent.getKnowledgeBase();
> this.kbaseLastUpdated = System.currentTimeMillis();
> }
>
>
> /**
> * {@inheritDoc}
> */
> public DecisionSession createSession ()
> {
> return new DecisionSession(kBase.newStatefulKnowledgeSession());
> }
>
>
> /**
> * {@inheritDoc}
> */
> public DecisionSession updateSession (DecisionSession oldSession)
> {
> // Create a new session from the current KnowledgeBase
> DecisionSession newSession =
> new DecisionSession(kBase.newStatefulKnowledgeSession());
>
> if(oldSession != null)
> {
> // "Clean" the old session of all stateless facts before update
> oldSession.removeAllStatelessKnowledge();
> // Copy all remaining facts to the new session
> newSession.uploadKnowledge(new
> ArrayList(oldSession.getAllFacts()));
> }
> return newSession;
> }
>
>
> /**
> * {@inheritDoc}
> */
> public boolean isSessionStale(DecisionSession decisionSession)
> {
> if(decisionSession.getCreationTime() < this.kbaseLastUpdated)
> {
> return true;
> }
> else
> {
> return false;
> }
> }
>
>
> /**
> * Create a KnowledgeBuilder from a ChangeSet.
> *
> * @param changeSet - The ChangeSet
> * @return A KnowledgeBuilder
> * @throws IllegalArgumentException if changeSet is not a valid
> ChangeSet.
> */
> private KnowledgeAgent createKnowledgeAgent(
> String changeSet,
> KnowledgeBase kbase)
> {
> // Configure KnowledgeAgentFactory
> configureAgentFactory();
> // Create the knowledge agent
> KnowledgeAgent agent = KnowledgeAgentFactory.newKnowledgeAgent(
> "classificationAgent",
> kbase);
>
> agent.applyChangeSet(ResourceFactory.newClassPathResource(changeSet));
> // Add actionListener for detecting rule updates
> agent.addEventListener(new xKnowledgeAgentEventListener());
> // Start the monitoring...
> ResourceFactory.getResourceChangeNotifierService().start();
> ResourceFactory.getResourceChangeScannerService().start();
> return agent;
> }
>
>
> /**
> * Configure the agentFactory.
> */
> private void configureAgentFactory()
> {
> // Enable incremental knowledge base build - false means that the
> // old knowledge base is "reused" and updated when there are
> // updated rules. True means that the old base is discarded and a
> new
> // one is created
> KnowledgeAgentConfiguration kagentConf =
> KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
> kagentConf.setProperty("drools.agent.newInstance", "false");
>
> // Configure the scanning interval - default is 60 sec.
> // (Scanning resources for changes...)
> ResourceChangeScannerConfiguration sconf =
>
> ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
> sconf.setProperty("drools.resource.scanner.interval", "30");
> ResourceFactory.getResourceChangeScannerService().configure(sconf);
> }
>
>
> /**
> * Create a KnowledgeBase. For CEP (Drools Fusion) decision service
> * use type = STATE_FULL otherwise use STATE_LESS.
> *
> * @param type - The type KnowledgeBase, state full or state less
> *
> * @return A KnowledgeBase
> */
> private KnowledgeBase createKnowledgeBase(DecisionSessionType type)
> {
> KnowledgeBase kbase;
> if(type.equals(DecisionSessionType.STATE_FULL)){
> KnowledgeBaseConfiguration config =
> KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
> config.setOption( EventProcessingOption.STREAM );
> kbase = KnowledgeBaseFactory.newKnowledgeBase( config );
> }
> else
> {
> kbase = KnowledgeBaseFactory.newKnowledgeBase();
> }
> return kbase;
> }
>
>
> /**
> * Get the ServiceType of this Service.
> *
> * @return The ServiceType of this service (STATE_FULL or STATE_LESS)
> */
> public DecisionSessionType getType ()
> {
> return type;
> }
>
>
> /**
> * When was the KnowledgeBase last updated.
> *
> * @return The timestamp (ms) for last update of KnowledgeBase
> */
> public long getLastUpdated()
> {
> return this.kbaseLastUpdated;
> }
>
>
> /**
> * Custom event listener for acting on events such as rule updates and
> * rule loading errors.
> */
> private class xKnowledgeAgentEventListener
> extends DefaultKnowledgeAgentEventListener
> {
>
> /**
> * Update the working copy of the KnowledgeBase when detecting
> * a updated one.
> *
> * @param event - The event signalling that the rule base has been
> updated
> */
> @Override
> public void knowledgeBaseUpdated (
> KnowledgeBaseUpdatedEvent event)
> {
> LOG.info("Detected updated rules! Rebuilding knowledgeBase!");
> long startTime = System.currentTimeMillis();
> kBase = kAgent.getKnowledgeBase();
> long endTime = System.currentTimeMillis();
> // Update the timestamp for when the knowledgeBase was updated
> kbaseLastUpdated = endTime;
> LOG.info("Rebuilding knowledgebase took " +
> (endTime - startTime) + "ms...");
> }
>
>
> /**
> * Log errors when problems updating the knowledge base.
> *
> * @param event - the Event signalling failure to load updated rules
> */
> @Override
> public void resourceCompilationFailed (
> ResourceCompilationFailedEvent event)
> {
> KnowledgeBuilderErrors errors =
> event.getKnowledgeBuilder().getErrors();
>
> if (errors.size() > 0)
> {
> LOG.error("Errors loading knowledge.");
> for (KnowledgeBuilderError error : errors)
> {
> LOG.error(error);
> }
> }
> }
> }
> }
>
>
>
>
>
> ________________________________________
> From: rules-users-bounces at lists.jboss.org [
> rules-users-bounces at lists.jboss.org] On Behalf Of Esteban Aliverti [
> esteban.aliverti at gmail.com]
> Sent: Monday, April 18, 2011 19:18
> To: Rules Users List
> Subject: Re: [rules-users] Dynamic updates of stateful sessions
>
> Maybe the new rules fail to compile. You can add an
> KnowledgeAgentEventListener to the agent to check for compilation errors.
> Could you post some code snippet showing how are you creating the kagent,
> the kbase, etc.
>
> You can take a look at some tests using newInstence=false here:
>
> https://github.com/droolsjbpm/drools/blob/master/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentIncrementalChangeSetTest.java
>
> Best Regards,
>
> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
>
> Esteban Aliverti
> - Developer @ http://www.plugtree.com
> - Blog @ http://ilesteban.wordpress.com
>
>
> On Mon, Apr 18, 2011 at 1:31 PM, Mattias Avelin <
> mattias.avelin at netlight.se<mailto:mattias.avelin at netlight.se>> wrote:
> Thanks for the swift reply!
>
> I have configured my Knowledge Agent to reuse the same KnowledgeBase (set
> drools.agent.newInstance property to "false" in my
> KnowledgeAgentConfiguration) as described in the Expert documentation. But
> my stateful session keeps using the old rules event though I can see from
> the log output that the Knowledgebase has been updated.
>
> /Mattias
> ________
> From: rules-users-bounces at lists.jboss.org<mailto:
> rules-users-bounces at lists.jboss.org> [rules-users-bounces at lists.jboss.org
> <mailto:rules-users-bounces at lists.jboss.org>] On Behalf Of Esteban
> Aliverti [esteban.aliverti at gmail.com<mailto:esteban.aliverti at gmail.com>]
> Sent: Monday, April 18, 2011 16:49
> To: Rules Users List
> Subject: Re: [rules-users] Dynamic updates of stateful sessions
>
> By default, the Knowledge Agent creates a new kbase when changes in the
> monitored resources are detected. So the stateful sessions you had are not
> going to "see" the changes because they belong to a different kbase.
> If you want the agent to apply the changes to the current kbase, you need
> to set drools.agent.newInstance property to "false" in knowledge agent
> configuration.
> You can read about this here:
> http://ilesteban.wordpress.com/2010/03/25/knowledge-agent-incremental-change-set-processing-and-binary-diff/
>
> If you are defining the kagent using spring, you can use the "newInstence"
> attribute of <kagent> bean.
>
> Best Regards,
>
> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
>
> Esteban Aliverti
> - Developer @ http://www.plugtree.com
> - Blog @ http://ilesteban.wordpress.com
>
>
> On Mon, Apr 18, 2011 at 11:41 AM, Mattias Avelin <
> mattias.avelin at netlight.se<mailto:mattias.avelin at netlight.se><mailto:
> mattias.avelin at netlight.se<mailto:mattias.avelin at netlight.se>>> wrote:
> We have a application in which we have both stateless & stateful sessions
> running. We're using the KnowledgeAgent and ChangeSets to automatically
> update our knowledge bases when the rules are changed.
> This works fine for our stateless sessions for which we are creating a new
> session for each request and if the rules have been updated this is
> reflected in next session we create.
>
> But for stateful sessions I'm not quite as sure on how to get it working. I
> can see in the logs that the KnowledgeBase is re-built when the
> KnowledgeAgent detects the updated rule files. But my "long running"
> session
> is does not reflect these changes (which it shouldn't right?). But how do
> we
> apply these changes to the stateful session without loosing all the facts I
> accumulated?
>
> The way I've solved it now is to keep a "last updated" timestamp for the
> knowledgeBase and a "created" timestamp for the session and then compare
> these before using the session. If the knowledgeBase's "update timestamp"
> is
> later that the sessions "creation timestamp" I create a new Session and
> then
> "manually" copy all facts from the former to the latter.
>
> Is this the way you would do this or is there a better way?
>
> Best Regards
>
> Mattias Avelin
>
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org<mailto:rules-users at lists.jboss.org><mailto:
> rules-users at lists.jboss.org<mailto:rules-users at lists.jboss.org>>
> https://lists.jboss.org/mailman/listinfo/rules-users
>
>
> ______________________________________________________________________
> This email has been scanned by the MessageLabs Email Security System.
> For more information please visit http://www.messagelabs.com/email
> ______________________________________________________________________
>
>
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org<mailto:rules-users at lists.jboss.org>
> https://lists.jboss.org/mailman/listinfo/rules-users
>
>
> ______________________________________________________________________
> This email has been scanned by the MessageLabs Email Security System.
> For more information please visit http://www.messagelabs.com/email
> ______________________________________________________________________
>
>
>
> _______________________________________________
> rules-users mailing list
> rules-users at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-users
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/rules-users/attachments/20110419/99a19eff/attachment.html
More information about the rules-users
mailing list