Skip to main content

skip to main content

developerWorks  >  WebSphere  >

Caching with the WebSphere Commerce marketing campaign engine

developerWorks
Document options

Document options requiring JavaScript are not displayed


Rate this page

Help us improve this content


Level: Introductory

Darl Crick (crick@ca.ibm.com), Software Architect, IBM 
Michael Rabbior (mrabbior@ca.ibm.com), Software Engineer, IBM 

06 Apr 2006
Updated Jan 2008

This article describes how to configure caching and optimize performance when using the WebSphere® Commerce marketing campaign engine in three simple steps.

Introduction

The features of the marketing campaign engine are functionally rich and can require a large amount of resources to execute. It is important that a system running the marketing campaign engine uses as much caching as possible to optimize the system's performance. It is also important to balance the feature and option you are going to use versus the performance of the system and the resources required. By spending time to configure caching for the marketing campaign engine, you can improve performance in the order of 20 times. The CPU utilization on a WebSphere Application Server will decline significantly, and the CPU on the database server will show reduced utilization. Furthermore, after you have configured the new cacheable command for the marketing campaign business logic and cached the JSP used to display the marketing content, you can use the features of the marketing campaign engine while maintaining optimal performance on your system. The main value is taking advantage of the functionally rich marketing campaign engine without having to sacrifice significant capacity or performance.

This article shows how to configure your system to take advantage of the changes made to the product. We have found this process enables the most effective caching along with enabling functionally rich features. In our experience, using this methodology gives you the biggest return for your invested time. At each step of the process, we address what does this step do, how do we do it, and why do we bother. The article assumes you are familiar with the basics of caching and the features of the marketing campaign engine.

This article is not a comprehensive resource on all things caching. There are DynaCache techniques and methods not covered in this document that are more appropriate for your specific scenario. For more information on these techniques, see Tutorial: Improve WebSphere Commerce performance with dynamic caching and Caching WebSphere Commerce pages with the WebSphere Application Server dynamic cache service. The assumption is that the current site is using request servlet (full page) caching for pages that contain the marketing initiatives.



Back to top


Step 1. Caching the marketing campaign engine logic

Why

The marketing campaign engine executes queries against the database to determine the marketing initiatives that the user qualifies to see. It does this on each request to the system that involves this feature. It then uses this result to display the appropriate content.

By command caching, you remove the execution of the Java™ code and database lookups on each request involving this feature. Only the code that needs to track information about the campaign will execute.

What

Command caching is a feature that allows you to cache the result of a command execution so that the result is returned without actually having to execute the code within the command.

How

You can create a cache-entry for the marketing campaign engine command using the command name and parameters or attributes. You can only have one cache-entry per command name.

Here is an example of a cache-entry that uses to cache the marketing campaign engine command:

<?xml version="1.0"?>
<!DOCTYPE cache	SYSTEM "cachespec.dtd">
<cache-entry>
<class>command</class>
<sharing-policy>not-shared</sharing-policy>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeEvaluateCmdImpl.class </name>
<cache-id>
   <component type="method" id="getEMarketingSpotName">
      <required>true</required>
   </component>
   <component type="method" id="getMaximumNumberOfAssociateCatalogEntries">
      <required>true</required>
   </component>
   <component type="method" id="getMaximumNumberOfCatalogEntries">
      <required>true</required>
   </component>
   <component type="method" id="getMaximumNumberOfCategories">
      <required>true</required>
   </component><component type="method" id="getMaximumNumberOfCollateral">
      <required>true</required>
   </component>
   
   <priority>1</priority>
</cache-id>
<dependency-id>eSpot</dependency-id>
<dependency-id>DC_userId</dependency-id>
</cache-entry>



Back to top


Step 2. Caching the display portion of the marketing campaign logic

Why

Caching the display portion of the promotion logic also improves performance because it reduces database lookups. This removes the execution of the Java code needed to build the display fragment associated to a particular set of marketing assets. Keep in mind that the more pieces there are to assemble into a page, the longer it takes to retrieve entries from the cache.

What

The personalized content, or content that changes depending on the circumstances, needs to be in a JSP fragment that is dynamically included by a parent page. This fragment is cached as individual cache entries, each representing a single permutation and combination of marketing collateral the fragment can display.

How

The first step in caching the personalized content of an eMarketingSpot defines a mapping between the URL request the client makes and the eMarketingSpots that the request will cause to be evaluated. This allows the marketing runtime to determine what the eMarketingSpot will display before the fragment will be run. This allows the marketing runtime to generate a cache key that represents the exact display result of the eMarketingSpot.

Here is an example from the xml/campaigns/cache/eMarketingSpotInvocationList.xml file where the mappings are stored:

<?xml version="1.0" encoding="UTF-8" ?>
<EMarketingSpotInvocationList>

 <StoreUsage storeId="0">
   <EMarketingSpotInvoker name="TopCategoriesDisplay"
    eMarketingSpotName="StoreHomePage" 
    maxAssociateCatalogEntries="20" 
    maxCatalogEntries="20" 
    maxCategories="20" 
    maxCollateral="20"/>
 </StoreUsage>

 <StoreUsage storeId="10001">
  <EMarketingSpotInvoker name="*" eMarketingSpotName="SideBar"/>
 </StoreUsage>

 <StoreUsage storeId="10001">
  <EMarketingSpotInvoker name="OrderItemAdd" eMarketingSpotName="SideBar"/>
 </StoreUsage>
</EMarketingSpotInvocationList>		
		

A StoreUsage element with a storeId of 0 indicates that the mappings defined within the element are applicable to all stores. A mapping with a name of "*" indicates the eMarketingSpot will be evaluated for every request to a store URL. Every time a request is made to a mapped eMarketingSpot, an attribute is added to the request name EMS_<emsName> that is used as a cache key for the fragment.

With this mapping file configured, an eMarketingSpot fragment can now be cached separately from its parent page. To do this, add an entry to cachespec.xml for the fragment. This entry must have the consume-subfragments property set to "false" so that it is not consumed with the parent JSP.

Here is an example from the sample cachespec.xml that caches the eMarketingspotDisplay.jsp separately from its parent page for an eMarketingSpot named <emsName>.

<cache-entry>
<class>servlet</class>
<name>/ConsumerDirect/include/eMarketingDisplay.jsp </name>
<property name="save-attributes">false</property>
<property name="store-cookies">false</property>
<property name="save-attributes">false</property>
<property name="do-not-consume">true</property>
<sharing-policy>not-shared</sharing-policy>
<cache-id>
      <component id="storeId" type="parameter">
         <required>true</required>
      </component>
      <component id="catalogId" type="parameter">
         <required>true</required>
     </component>
     <component id="EMS_<emsName>" type="attribute">
         <required>true</required>
     </component>
</cache-id>
<dependency-id>eSpot</dependency-id>
</cache-entry>

You must have an entry made for each fragment you wish to cache separately.

The fragment being excluded must be self-executing, and cannot depend on attributes set by the parent JSP. However, it can use the attribute from the marketing campaign engine because these attributes will not be set for you on each request that involves a campaign. To determine if the fragment is self-executing after the cachespec.xml is configured, hit the servlet's page. Next, use the cachemontor to invalidate the child fragment. Then, execute the page request to confirm the execution of the fragment is successful. If so, that fragment is self-executing. Note that not all fragments in WebSphere Commerce are self-executing.

The cache-entry for the parent servlet contains values for those parameters passed into the fragment using the jsp:include or c:import tags. This means that on a cache hit, the parameters passed from the parent to the fragment are not regenerated. To pass new values to the fragment, you must invalidate and then re-execute the parent JSP.

After creating the necessary cache policies the campaign caching component in WebSphere Commerce, enable the instance configuration XML. To do this, locate the CampaignsCachingComponent in the instance configuration XML, and set the enable attributes to "true". The component XML looks like the following example:

<component
   compClassName="com.ibm.commerce.campaigns.cache.CampaignsCachingComponent"
   enable="true" name="CampaignsCachingComponent">
   <property display="true">
      <start enabled="true"/>
   </property>
</component>

When enabled, this component allows the campaigns runtime to support caching JSP fragments that contain the campaign content.



Back to top


Step 3. Invalidating the marketing campaign engine command and JSPs

Why

We encourage defining invalidation rules to automate the invalidation of cache entries. If you do not have invalidation rules configured, then you need to invalidate all of the cache when content changes. This means that everything will be removed from the cache, and not just the changed pages. We do not recommend the invalidation of the complete cache. It may be common for the business user to change the campaigns that they are running, and after that has been done, they will expect the system to change immediately. The business user cannot invalidate the cache in order to have the site reflect their changes.

What

The simplest way to invalidate cache entries associated to the marketing campaign engine is to use the command-based invalidation. This method is useful for changes made by the tooling provided to update the campaigns in the system. The execution of the tools commands to update the system are used to invalidate the promotion cached command and JSP.

You can also invalidate entries in the cache through the cache monitor, but automating the invalidation reduces the risk of someone invalidating the wrong content.

A final way to configure automatic cache invalidation is using the CACHEIVL table in combination with database triggers or with an insert statement.

How

To trigger cache invalidation by a command, you must first declare dependency IDs for the cache entries you want to invalidate. The dependency IDs represent the components that, should they change, invalidate the content of this cache-entry. The following sample shows the cache-entry for an eMarketingSpot fragment, including the possible dependency ID:

<cache-entry>
<class>servlet</class>
<name>/ConsumerDirect/include/eMarketingDisplay.jsp </name>
<property name="save-attributes">false</property>
<property name="store-cookies">false</property>
<property name="save-attributes">false</property>
<property name="do-not-consume">true</property>
<sharing-policy>not-shared</sharing-policy>
<cache-id>
  <timeout>3600</timeout>
      <component  id="storeId" type="parameter">
         <required>true</required>
      </component>
      <component id="catalogId" type="parameter">
         <required>true</required>
      </component>
      <component id="EMS_<emsName>" type="attribute">
         <required>true</required>
     </component>
</cache-id>
<dependency-id>eSpot</dependency-id>
</cache-entry>

Next, we need a command that is recognized by the dynamic cache. You must write this command to the WebSphere Command Framework: its implementation class must extend from CacheableCommandImpl (in the com.ibm.websphere.command package). To simplify command writing for command-based invalidation, WebSphere Commerce has updated the abstract classes, ControllerCommandImpl, and TaskCommandImpl to extend from CacheableCommandImpl. Any commands extend from these abstract classes also extends from CacheableCommandImpl. Therefore, they are eligible for command-based invalidation.

Finally, make an entry for the command in your cachespec.xml that contains definitions for the invalidation IDs you want to generate. The sample below listens for the WebSphere Commerce commands that indicate changes to an order and generates invalidation IDs to invalidate the cache entries with matching dependency IDs:

<cache-entry>
<class>command</class>
<sharing-policy>not-shared</sharing-policy>
<name>com.ibm.commerce.tools.segmentation.SegmentAddUserControllerCmdImpl</name>
<name>com.ibm.commerce.tools.segmentation.SegmentDeleteControllerCmdImpl</name>
<name>com.ibm.commerce.tools.segmentation.SegmentDuplicateControllerCmdImpl</name>
<name>com.ibm.commerce.tools.segmentation.SegmentRemoveUserControllerCmdImpl</name>
<name>com.ibm.commerce.tools.segmentation.SegmentSaveControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeDeleteControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeDisableControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeSaveControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeScheduleDeleteControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignInitiativeScheduleSaveControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignCollateralDeleteControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignCollateralSaveControllerCmdImpl</name>
<name>com.ibm.commerce.tools.campaigns.CampaignCollateralUpdateCmdImpl</name>
<name>com.ibm.commerce.tools.epromotion.commands.RLPromotionDeleteControllerCmdImpl</name>
<name>com.ibm.commerce.tools.epromotion.commands.RLPromotionPublishControllerCmdImpl</name>
<name>com.ibm.commerce.tools.epromotion.commands.RLPromotionSaveControllerCmdImpl</name>
<invalidation>eSpot</invalidation>
</cache-entry>

Notes:

  • To invalidate, the eMarketingSpot must have a dependency ID that matches the invalidation ID being generated. The sample eMarketingSpot entry is invalidated in this case.
  • The list of commands above is only a sample of the commands that might be needed to invalidate the cache in some cases. Make sure to include all other commands required when eMarketingSpot cache entries depend on business objects that are not touched by the commands above.

A final way to invalidate cache content is by making entries to the CACHEIVL table. You can change the frequency of the DynaCacheInvalidation command by referring to the documentation on the scheduler in the WebSphere Commerce Administration Guide on how to edit, delete, and schedule a new job. The WebSphere Commerce scheduler runs a DynaCacheInvalidation command at a set interval. This command processes the entries in the CACHEIVL table as follows:

  • The "clearall" string value in the TEMPLATE or DATA_ID columns of the CACHEIVL table is used by DynaCacheInvalidation to clear the cache by dynamic cache invalidation API (clear).
  • If the TEMPLATE column is set, then the DynaCacheInvalidation command calls the dynamic cache invalidation API (invalidateByTemplate) and uses the name as the template ID. If the "clearall" string value (which is case insensitive) is found in TEMPLATE column, then the DATA_ID column is ignored and the DynaCacheInvalidation command clears the cache. If the TEMPLATE column is not empty, the command invalidates by the template ID, ignoring the DATA_ID column.
  • If the DATA_ID column is set and the template name is not set, then the DynaCacheInvalidation command calls the dynamic cache invalidation API (invalidateById) and uses the DATA_ID as the ID. If the TEMPLATE column is empty and the "clearall" string value is found in the DATA_ID column, then the command clears the cache.
  • When the dynamic cache invalidation API is called, it invalidates the cache entries.

This is a sample insert to invalidate the marketing campaign engine command and JSP:

INSERT INTO cacheivl (template, dataid, inserttime) values (NULLIF('A', 'A'),  
'eSpot', CURRENT TIMESTAMP);

You are not restricted to one of the invalidation techniques mentioned. Your cache invalidation setup can combine any or all of them to ensure that you can achieve the necessary invalidation for your system.



Back to top


Conclusion

The WebSphere Commerce Performance and Marketing development teams have developed a methodology that configures caching when using the features of the marketing campaign engine. In our experience, these three steps achieve optimal performance. At each step, we have explained what motivation lies behind it, and how you too can accomplish what we have set out to do.



Resources

Learn

Discuss


About the authors

Darl Crick is the Chief Architect for WebSphere Commerce Performance and Business Runtime at the IBM Toronto Software Lab, Canada.


Michael Rabbior is the Technical Team Lead for WebSphere Commerce Marketing and Merchandising at the IBM Toronto Software Lab, Canada.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top