Flush the Cache Droplet Upon CA Deployments

Hopefully you’re already using the ATG Cache Droplet extensively in your ATG eCommerce application, as I recommended in my ATG Performance Tuning post on Improving JSP Serving Time for an ATG Application.  If you are, you’re probably using a smaller value for the cacheCheckSeconds parameter than you’d like, in order to prevent stale data after CA deployments update the catalog, media, or promo repositories.

You can solve this problem by using a component triggered by Deployment Events from the DeploymentAgent, which after a successful deployment flushes the Cache Droplet’s cache.  This should allow you to set a very long cache expiration time using the cacheCheckSeconds param, and not have to worry about displaying outdated data.

I’ve added this code into the open source ATG eCommerce framework Foundation, hosted by Spark::red, the best ATG Hosting Company :)

There are three parts to this solution: the Java class, it’s properties file, and adding it to the DeploymentAgent’s list of event listeners.

DeploymentEventCacheDropletInvalidator.java

/**
 * Copyright 2009 Devon Hillard (devon@digitalsanctuary.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.foundation.deployment;

import atg.deployment.common.event.DeploymentEvent;
import atg.deployment.common.event.DeploymentEventListener;
import atg.droplet.Cache;
import atg.nucleus.GenericService;
import atg.nucleus.ServiceException;

/**
 * The Class DeploymentEventCacheDropletInvalidator will flush the Cache droplet's cache upon a successful CA
 * deployment.
 * 
 * @author Devon Hillard
 */
public class DeploymentEventCacheDropletInvalidator extends GenericService implements DeploymentEventListener {

    /** The Cache Droplet. */
    private Cache mCacheDroplet;

    /** The event state. */
    private int mEventState;

    /** The active. */
    private boolean mActive;

    /**
     * Deployment event handling method. This will flush the Cache droplet's cache after a CA deployment completes.
     * 
     * @param pEvent the deployment event
     * 
     * @see atg.deployment.common.event.DeploymentEventListener#deploymentEvent(atg.deployment.common.event.DeploymentEvent)
     */
    public void deploymentEvent(final DeploymentEvent pEvent) {
        if (isActive() && (pEvent.getNewState() == getEventState())) {
            if (isLoggingInfo()) {
                logInfo("DeploymentEventCacheDropletInvalidator.deploymentEvent:" + "Deployment has completed.");
            }
            getCacheDroplet().flushCache();
            if (isLoggingInfo()) {
                logInfo("DeploymentEventCacheDropletInvalidator.deploymentEvent"
                        + "Cache droplet cache has been flushed.";);
            }
        }
    }

    /**
     * Do start service.
     * 
     * @throws ServiceException the service exception
     * 
     * @see atg.nucleus.GenericService#doStartService()
     */
    @Override
    public void doStartService() throws ServiceException {
        if (isLoggingInfo()) {
            logInfo("DeploymentEventCacheDropletInvalidator.doStartService:" + "starting up.");
        }
        if (getCacheDroplet() == null) {
            throw new ServiceException("DeploymentEventCacheDropletInvalidator: cache droplet was not set.";);
        }
        if (getEventState() == 0) {
            throw new ServiceException("DeploymentEventCacheDropletInvalidator: event state was not set.");
        }
    }

    /**
     * Do stop service.
     * 
     * @throws ServiceException the service exception
     * 
     * @see atg.nucleus.GenericService#doStopService()
     */
    @Override
    public void doStopService() throws ServiceException {
        if (isLoggingInfo()) {
            logInfo("DeploymentEventCacheDropletInvalidator.doStopService:" + "stopping.");
        }
    }

    /**
     * Gets the Cache Droplet.
     * 
     * @return the cacheDroplet
     */
    public Cache getCacheDroplet() {
        return this.mCacheDroplet;
    }

    /**
     * Sets the Cache Droplet.
     * 
     * @param pCacheDroplet the cacheDroplet to set
     */
    public void setCacheDroplet(final Cache pCacheDroplet) {
        this.mCacheDroplet = pCacheDroplet;
    }

    /**
     * Gets the event state.
     * 
     * @return the event state
     */
    public int getEventState() {
        return this.mEventState;
    }

    /**
     * Sets the event state.
     * 
     * @param pEventState the new event state
     */
    public void setEventState(final int pEventState) {
        this.mEventState = pEventState;
    }

    /**
     * Checks if is active.
     * 
     * @return true, if is active
     */
    public boolean isActive() {
        return this.mActive;
    }

    /**
     * Sets the active.
     * 
     * @param pActive the new active
     */
    public void setActive(final boolean pActive) {
        this.mActive = pActive;
    }

}

DeploymentEventCacheDropletInvalidator.properties

$class=org.foundation.deployment.DeploymentEventCacheDropletInvalidator
$scope=global

# If true, this service will invalidate the Cache droplet's cache when the appropriate deployment event is fired.
active=true

# The cache droplet to invalidate.  Defaults to the standard Cache droplet.
cacheDroplet=/atg/dynamo/droplet/Cache

# The deployment event's newState to trigger a cache flush of the Cache droplet.
# IDLE = 1;
# DEPLOYMENT_COMPLETE = 2;
# DEPLOYMENT_DELETED = 7;
# EVENT_INTERRUPT = 6;
# ERROR = 3;
# BEGIN_LOCK = 201;
# DONE_LOCK = 202;
# ERROR_LOCK = 203;
# BEGIN_PREPARE = 301;
# DONE_PREPARE = 302;
# ERROR_PREPARE = 303;
# BEGIN_CREATE = 401;
# DONE_CREATE = 402;
# ERROR_CREATE = 403;
# BEGIN_INSTALL = 501;
# DONE_INSTALL = 502;
# ERROR_INSTALL = 503;
# BEGIN_LOAD = 601;
# DONE_LOAD = 602;
# ERROR_LOAD = 603;
# BEGIN_APPLY = 701;
# BEGIN_APPLY_COMMITTED = 702;
# DONE_APPLY = 703;
# ERROR_APPLY = 704;
# ERROR_APPLY_COMMITTED = 705;
# BEGIN_ACTIVATE = 801;
# DONE_ACTIVATE = 803;
# ERROR_ACTIVATE = 804;
# BEGIN_STOP = 901;
# DONE_STOP = 902;
# ERROR_STOP = 903;
eventState=1

/atg/epub/DeploymentAgent.properties

deploymentEventListeners+=\
	/foundation/deployment/DeploymentEventCacheDropletInvalidator
	

——————————
Edit: at least in our cluster, the DEPLOYMENT_COMPLETE (2) event is never triggered on the client side by the DeploymentAgent, so I’ve switched this to use the transition to IDLE (1).

2 thoughts on “Flush the Cache Droplet Upon CA Deployments

  1. Hi, great stuff you’ve put up. I am quite new to ATG and have a scenario where there are 3 different ATG deployments pointing to the same repository. We are having a common piece of code and plan to package this as a module and load it in the 3 deployments. Is this good as a practice? If this approach is ok, how do we achieved cache management given the distributed nature of these 3 deployments. Any help would be great…..

    • Raj,

      thanks! I’m not sure what you mean by 3 different deployments pointing to the same repository. Three projects? Three CA instances? Three workflows? 3 app servers?

      Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>