Monday, January 25, 2021

SXA cache multilingual datasources

Sitecore SXA datasource caching

I bumped into an issue a while ago related to datasources and how they are handled in a Sitecore SXA environment. This is an overview of our setup:

  • using SXA (Sitecore Experience Accellerator) for Sitecore 9.2
  • a PageList component with a variant
  • an Item Query that refers to custom code (a query starting with "code:" - more info here)
  • custom code that return a list of items and is language dependent (meaning: the list of items is different per language)  

That last one is actually the trigger for my issue as I had used custom coded Item Queries before and they seemed to work fine. Even in a multilingual setup. But in this particular case the results per language were actually different items - not just the same items with translated content.

I noticed that there was some caching issue and in the end I contacted Sitecore Support and placed some information on Sitecore StackExchange: "Custom SXA PageList datasource is not working in multilingual environment".


ResolveRenderingDatasourceCache

With some research I found there was an issue with the ResolveRenderingDatasourceCache. That cache is not language dependent and so my results were wrong.

A first possible solution would be to disable that cache by patching the config setting XA.Foundation.LocalDatasources.ResolveRenderingDatasourceCache.Enabled to false. This works, but of course that turns off this cache completely.

I noticed that the resolveRenderingDatasource pipeline has 2 relevant functions:
  • Sitecore.XA.Foundation.LocalDatasources.Pipelines.ResolveRenderingDatasource.GetFromCache
  • Sitecore.XA.Foundation.LocalDatasources.Pipelines.ResolveRenderingDatasource.SetCache
This brings us to solution two, which would disable the cache only for datasources that start with "code:": we can override the process method in the SetCache class and add code like this:
if (args.DefaultDatasource.StartsWith("code")) { return; }
This works as well, we keep the cache for most of our datasources but it is still disabled for the coded ones. And so I thought of another final solution: let's check the generation of the cache key!

BuildCacheKey

Both methods (GetFromCache and SetCache) are using a BuildCacheKey method from an underlying ResolveRenderingDatasourceCacheBase class. This method seemed not to be used anywhere else so I decided to override that one and use it in both the GetFromCache and SetCache classes.
protected override string BuildCacheKey(ResolveRenderingDatasourceArgs args)
{
    var key = base.BuildCacheKey(args);
    if (!string.IsNullOrEmpty(key) && args.DefaultDatasource.StartsWith("code:", StringComparison.OrdinalIgnoreCase))
    {
        key += Sitecore.Context.Language.Name;
    }

    return key;
}
This solution makes the cache work in all situations. We keep the current implementation for most datasources (as those are not language dependent) and add the language to the key for those that might (the ones starting with "code:" and you might also add those starting with "query:" if needed).
 
Patch the processors as:
<sitecore>
  <pipelines>
    <resolveRenderingDatasource>
      <processor type="Sitecore.XA.Foundation.LocalDatasources.Pipelines.ResolveRenderingDatasource.GetFromCache, Sitecore.XA.Foundation.LocalDatasources" resolve="true">
        <patch:attribute name="type">Feature.Caching.Rendering.Datasources.GetFromCache, Feature.Caching</patch:attribute>
      </processor>
      <processor type="Sitecore.XA.Foundation.LocalDatasources.Pipelines.ResolveRenderingDatasource.SetCache, Sitecore.XA.Foundation.LocalDatasources" resolve="true">
        <patch:attribute name="type">Feature.Caching.Rendering.Datasources.SetCache, Feature.Caching</patch:attribute>
      </processor>
    </resolveRenderingDatasource>
  </pipelines>
</sitecore>

A change request has been made to adjust this in a future version of SXA - but in the meantime you can easily patch it yourself if needed. Keep the cache and enable different results in different languages!


 

2 comments:

  1. I am trying to implement approach two. I created a class which inherits class ResolveRenderingDatasourceCacheBase and implements method BuildCacheKey. I added the patch file also as described in article but I am getting error "Error: Could not find method: Process. Pipeline: /sitecore[database=”SqlServer”.

    Am I missing anything. Can you please help me on this

    ReplyDelete
    Replies
    1. There seems to be something wrong with your config, but as this is not the best place to help you with issues like that: please find me (and others) on Sitecore StackExchange https://sitecore.stackexchange.com (or Slack) to help you with this.

      Delete