Asset Rendition Caching Problem and Solution

05287_Asset-Rendition-Caching-Problem-and-Solution

We’ve talked before about the dissonance between Adobe Experience Manager’s Publish and Dispatcher instances, but this dissonance is not limited to content pages; another case that comes up often is when caching image renditions from DAM Assets. If you directly refer to the Asset’s rendition through the Dispatcher, you might have found a surprising result when you then tried to render the Asset node directly. Let’s break down what’s happening here…

Explanation
The Dispatcher caches content. It doesn’t do anything particularly intelligent in the caching process – it just asks the Publish node for a file – say, “en.html” – and stores whatever results are returned until they get invalidated or flushed.

Demonstrating the Problem
An easy way to put an image on a page is to write the DAM path into the src of an img element.

which gives

Say we have /content/dam/site/dog.jpg in the DAM. If we hit that, we see an image of a dog. The Asset Upload Workflow also makes a bunch of renditions, so if we hit /content/dam/site/dog.jpg/jcr:content/renditions/cq5dam.thumbnail.48.48.png, we see the same image rendered at a constant 48×48 pixels.

If the requests are issued in that order, we would find a file on the Dispatcher at /content/dam/site/dog.jpg which contains the full-sized image, while the latter is served correctly, but never cached.

If we request the thumbnail rendition first, we see a cached file named something like /content/dam/site/dog.jpg/_jcr_content/renditions/cq5dam.thumbnail.48.48.png. But when we request /content/dam/site/dog.jpg to see the original asset, we get a 403 response from the Dispatcher because “dog.jpg” is a directory leading to the thumbnail, rather than a file.

To make the problem even more painful, it’s not uncommon to have multiple Dispatchers in some kind of load balanced environment, and you may end up with the requests coming in using the “successful” ordering on one Dispatcher, while going in the “broken” order on another, leading to inconsistent errors depending on which Dispatcher serves a particular request.

Possible Solutions
We have found a few different ways of working around this issue; with the flexibility of AEM, there are probably even more ways, but these are kind of our “default set” of tools we reach for when we find ourselves in this situation. Having multiple solutions allows us some flexibility to pick and choose our preferred option based on other project constraints.

Solution #1: Use the Named Image Transform Servlet
If you are using ACS Commons, you can use the Named Image Transform Servlet. It will produce paths that look like /content/dam/dog.png.transform/my-transform-name/image.png, which will not create conflicting cache.

If you are not using ACS AEM Commons – why not? See our extended series on the array of useful items contained in this Adobe-sponsored, open source package.

Solution #2: Put the image in a subresource and use the image servlet on parbase (/libs/foundation/components/parbase/img.GET.java). There are two steps to do this:
1. Get the subnode in place with the dialog

By doing ./image-resource/propertyName in the name fields, we are creating a subresource at image-resource (or whatever arbitrary name we selected) as a child of our current resource, and putting propertyName in it as a property. You can also pick stuff up the same way using ${properties[‘image-resource/propertyName’]}. We have noted some difficulty leveraging this method at page creation time in AEM 6.1, where the code that handles the dialog appears to be too simplistic to obey this directive.

2. Use the subresource to render the image

which gives

${resource.path} gives us the path of the current resource, which is a particular node with its sling:resourceType equal to our component, which has an image-resource subresource.

This puts the cached file at /content/site/en/page/jcr:content/parsys/…/image-resource.img.png, which will not conflict with the DAM path. However, this does take us back to the original “dissonance” problem of having stale cache if the image is edited in the DAM and the path doesn’t change.

Solution #3: Reference the “original” rendition
Using one of the various forms of content rewriting, you can detect any attempts to directly reference the Asset node and append “/jcr:content/renditions/original” to the requested path, so that the Dispatcher consistently sees the Asset node as a directory containing “rendition” items.

At Axis41, our general preference is to lean toward the first option (namely, the ACS AEM Commons Named Image Transform); however, it’s useful to know there are other methods as well, in case you ever find yourself in need of an alternative.

If you have run into this problem and found other solutions that you think we’re overlooking, we’d love to hear from you at [email protected].