Programmatic Cache Deletion

Every AEM infrastructure leverages the dispatcher for one or all of caching, security, and load balancing. As far as caching is concerned, many AEM customers rely on flush agents to keep things fresh. Flush agents are great as they recognize activation requests for page content and then send a flush request to their configured dispatcher but often times, these flush agents are not enough. For example, consider a site that leverages MSM extensively. Unless you write your own custom activation flow that replicates all live copies whenever their blueprint is activated, you’ll find that only the blueprint’s page gets refreshed. This is as expected from a technical standpoint but often doesn’t jive with the business’s thought process. Other times, the flush agent can just fail for whatever reason leaving your massive production content deployment 90% new hotness and 10% old stodginess. Because of these and other situations that could arise when messing around with cache, many customers will rely on flush agents for one-off activations but for production content deployments of any substance, will prefer to just blow it all away.

Recently I implemented a utility for a client such that they can clear a single or all dispatchers of their cache with a single click. To date they’d been using a shell script living directly on the dispatchers. During production deployments, they’d ssh into each dispatcher one by one and run the script. That script was basically rm -rf on that dispatcher’s docroot. So, to do the same in code, I threw together the following:

  1. Author-side TouchUI utility makes GET request to servlet on that same author instance, passing the relevant publish instance(s) as parameter(s).
  2. Servlet on above author instance makes GET request to servlet on each relevant publish instance requesting a cache deletion.
  3. Servlet on each publish instance makes POST request to relevant dispatchers to formally make the cache deletion request.
  4. Publish-side servlet responds with status code and message to author-side servlet.
  5. Author-side servlet checks the status code and message and builds a relevant response that then gets passed to the client.
  6. Client presents user with success or failure messaging
  7. ???
  8. Profit!

A few things to note about the above flow:

  • As is good practice, the dispatchers were configured to only allow cache invalidation/deletion requests from themselves or from their associated publish instance. As a result, I had to make the formal deletion request from publish and not from author.
  • Since I was already going to have to make the formal request from publish, that means I’d have to call publish from author in some way. I opted to go server-side first on author before calling over to publish as going author client-side to publish server-side comes with its own security issues (not least of which is the good ‘ol Javascript same-origin policy).

The actual deletion request, which is made via POST from my publish-side servlet, looks as follows:

HttpClient client = new HttpClient();
PostMethod post = new PostMethod(agent.getConfiguration().getTransportURI());

post.setRequestHeader("CQ-Action", "DELETE");
post.setRequestHeader("CQ-Handle", "/");
post.setRequestHeader("Content-Length", "0");
post.setRequestHeader("Content-Type", "application/octet-stream");


In the above, the variable agent is an instance of Agent and I retrieve this agent via an ID that I passed over from author. That ID is the ID for the relevant flush agent that’s configured on this publish instance. I then use the transportURI of that flush agent to get the appropriate URL for the dispatcher for which cache needs deleted. As for the deletion itself, passing a CQ-Handle of just “/” means “blow away everything under the configured docroot” – which is exactly what we want.