1

We have a setup where we use Craft's {% cache %} tag to improve performance of certain computing-cost-intensive pages.

The expected way to do this is by using the {% cache %} tage and probably improve its usage with certain attributes like globally, using key, for and so on.

The only problem: I have no control, when the content inside the {% cache %} tag is recreated, meaning I can not enforce it. I can only limit its lifetime, but I can not ensure the content is recreated without losing or clearing it's cached version before in one war or another. Yes, there are options to prevent it from caching, but in this case the cache does not get written. In other words: I first have to loose my performance improvement of the {% cache %} tag before I can refresh it.

My idea would be to have a newly introduced boolean parameter recreate on the {% cache %} tag which does not check if a cached version exists but in any case overwrites it. This recreate option could be enabled e.g. with a certain request header or something which could be used in a controlled way, e.g. by a crawler which ensures the cache stays up to date without risking too many empty caches at the same time.

What do you think of this? Is there any other way to achieve this?

2 Answers 2

2

The only way to regenerate cached content in Craft is by clearing the existing cache data and allowing it to be regenerated when accessed again. It sounds like you’re asking for a cache warming feature, which currently does not exist.

Since you can’t always know the context in which the cached content was originally generated, regenerating it is not trivial. If, for example, you wanted to regenerate cached content on a page with URI /page then you could first clear that specific cache and then trigger a request to that URI. But this is complicated by the fact that the cached content may exist on more pages, depending on the key used and whether it was cached globally or not.

My feeling is that what you’re asking for is beyond the scope of what the {% cache %} tag is intended to do. Perhaps you’ve been spoiled by Blitz?!

If you have deep knowledge of what is being cached, and have the ability to regenerate it predictably, then it may be possible to pull off some sort of cache regeneration process, as mentioned above. But from experience I can tell you that this stuff can get complex, fast.

1
  • In general you are right, caching is a complex subject and who should know better than you. But my suggested use case is quite simple, as it does the same as the cache tag would normally do including all problems you have when sharing cached content between multiple pages. Therefor my suggestion for a simple additional parameter should not add complexity from my point of view. But maybe I've been hit by a Blitz and don't see it clearly... :-) Commented May 3 at 8:41
1

We found a workaround to get the expected behavior:

  • We created a custom TWIG function replaceCache(...), that is capable of replacing the content of a cached entry using the methods of the
  • When we want to "recreate" (as I called it in my inital post), we add a certain GET param to our URL
  • If this GET param is detected, the {% cache %} tag uses a temporary cache key instead of the normal one (which we also specify), so the content of the tag is actually saved to a different key than normally
  • Also if the GET param is detected, the custom TWIG function replaceCache is called after the cache tag closes and it will replace the content of the regular key with the content of the temporary one.

This is the TWIG method we use:

    public function replaceCache($from, $to, ?string $duration = null)
    {
        $cacheService = Craft::$app->getTemplateCaches();
        // read the temporary cache
        $body = $cacheService->getTemplateCache($from, true);

        // write body to normal cache key    
        $cacheService->startTemplateCache(false, true);
        $cacheService->endTemplateCache($to, true, $duration, false, $body);
        // clear the temp cache
        $cacheService->deleteCachesByKey($from);
    }

We then set the duration for the cache tag to e.g. 10 mins and force recreation by calling the pages' URLs with our GET param every 9 mins with a cronjob.

This way the cache is always warm. Dirty workaround to a realworld need :-)

BTW: here's my FR: https://github.com/craftcms/cms/discussions/15005

1
  • Interesting approach! I’ll be following the discussion closely ;)
    – Ben Croker
    Commented May 23 at 7:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.