How to improve the performance of the rule engine

Old promotion rules

Unpublish all promotion rules which are triggered by old coupons which are inactive. A cronjob can be created to regularly remove these unused rules

Log the calls to the hybris code

Log all events generated by the rule engine

The details of the logged events are not very useful.

Create the following class:

package org.areko.core.ruleengineservices;

import de.hybris.platform.ruleengine.RuleEvaluationContext;
import de.hybris.platform.ruleengine.impl.DefaultPlatformRuleEngineService;

import java.io.IOException;
import java.nio.file.Files;
import java.util.Collection;
import java.util.function.Supplier;

import javax.annotation.PostConstruct;

import org.apache.commons.collections.CollectionUtils;
import org.kie.api.KieServices;
import org.kie.api.command.BatchExecutionCommand;
import org.kie.api.logger.KieRuntimeLogger;
import org.kie.api.runtime.ExecutionResults;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This implementation logs the events generated by the rule engine
 */
public class ArLoggingPlatformRuleEngineService extends DefaultPlatformRuleEngineService
{
    private static final Logger LOGGER = LoggerFactory.getLogger(ArLoggingPlatformRuleEngineService.class);

    private KieServices kieServices;

    // OOTB Code adding the logger
    protected Supplier<ExecutionResults> executionResultsSupplierWithStatefulSession(KieContainer kContainer, BatchExecutionCommand command, RuleEvaluationContext context) {
        return () -> {
            KieSession kieSession = (KieSession)this.getKieSessionHelper().initializeSession(KieSession.class, context, kContainer);
            LOGGER.debug("Executing KieSession.execute for releaseId [{}]", kContainer.getReleaseId());
            final KieRuntimeLogger kieRuntimeLogger = addAuditLogger(kieSession);

            ExecutionResults executionResults;
            try {
                executionResults = (ExecutionResults)kieSession.execute(command);
            } finally {
                Collection factHandles = kieSession.getFactHandles();
                if (CollectionUtils.isNotEmpty(factHandles)) {
                    factHandles.stream().filter(FactHandle.class::isInstance)
                        .map(FactHandle.class::cast)
                        .forEach(h -> kieSession.delete((FactHandle) h));
                }

                LOGGER.debug("Disposing the session: {}", kieSession);
                kieSession.dispose();
                kieRuntimeLogger.close();
            }

            return executionResults;
        };
    }

    private KieRuntimeLogger addAuditLogger(final KieSession kieSession)
    {
        try
        {
            return this.kieServices.getLoggers().newFileLogger(kieSession, Files.createTempFile("drools.audit", "log.xml").toAbsolutePath().toString());
        } catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }

    @PostConstruct
    protected void setUp() {
        this.kieServices = this.getRuleEngineBootstrap().getEngineServices();
    }
}

Secondly add this bean definition to one of the spring application context of your hybris workspace:

    <alias name="arLoggingPlatformRuleEngineService" alias="platformRuleEngineService" />
    <bean id="arLoggingPlatformRuleEngineService" parent="defaultPlatformRuleEngineService"
          class="org.areko.core.ruleengineservices.ArLoggingPlatformRuleEngineService">
    </bean>

After you start the server, create a cart, add products and a voucher, you will get the file /tmp/drools.audit.log.xml.log containing the logged events. You can use the following command to make the event IDs readable:

sed -i 's/<type>1<\/type>/<type>INSERTED<\/type>/g' /tmp/drools.audit.log.xml.log; sed -i 's/<type>2<\/type>/<type>UPDATED<\/type>/g' /tmp/drools.audit.log.xml.log; sed -i 's/<type>3<\/type>/<type>RETRACTED<\/type>/g' /tmp/drools.audit.log.xml.log; sed -i 's/<type>4<\/type>/<type>ACTIVATION_CREATED<\/type>/g' /tmp/drools.audit.log.xml.log; sed -i 's/<type>6<\/type>/<type>BEFORE_ACTIVATION_FIRE<\/type>/g' /tmp/drools.audit.log.xml.log; sed -i 's/<type>7<\/type>/<type>AFTER_ACTIVATION_FIRE<\/type>/g' /tmp/drools.audit.log.xml.log;

Find slow performing rules using drools metrics

FIXME Drools comes with a logging module How to use MetricLogUtils but it don't work with the drool version shipped with SAP commerce. This module won't work with any drools version under 7.41.0.Final because it overrides the class PhreakNetworkNodeFactory to set up the logging beans. This class is absent in older versions of drools.

Chapter 20. Performance tuning considerations with DRL This is not useful with hybris because most of the customer only have promotion rules with coupons. This increases the performance of the engine and leaves no room for optimizations.

Documentation of drools 7.21

– Based on SAP commerce 2105

Discussion

Enter your comment. Wiki syntax is allowed: