0

I have a view that takes a while to build when the cache is cold (around 11s). When the cache is hot, the view loads quickly, of course (around 100ms). I'm using tag-based caching for this view, so when I add a node, and reload the view, it takes a while to generate, since the cache is being rebuilt during the request.

Is there a way to proactively rebuild the cache? I see two options, neither of which I know how to do:

  • Warm up the view's cache on the next cron run, and run cron very often. For this I would need a way to check whether the cache is cold for that specific view. This is not ideal, because unlucky anonymous users could still visit the view before cron and get a bad experience.
  • Warm up the view's cache directly after it's invalidated, i.e. during or directly after the POST request that created the new node. In my use case, it's better to let the user that creates nodes wait than to let some random unsuspecting anonymous users wait while they unwittingly hit a cold cache.

Any ideas?

4
  • 11 seconds is quite a long time. Have you executed an EXPLAIN on the raw query to find out why it is so slow?
    – cilefen
    Jun 29, 2022 at 23:23
  • Are you pulling references of references or trying to show dozens of rendered content items per page?
    – Kevin
    Jun 30, 2022 at 0:37
  • This is an RSS XML view display, with hundreds of nodes. More specifically, it's from the simple_sitemap module. But I don't think that is relevant to the question. Caching slow views is a more general problem. Jun 30, 2022 at 10:09
  • If you have a View behind a route then use renderRoot() to render the View. In this case don't add the cache tags bubbled up in the renderRoot() call, only add your custom cache tag to the response, which you invalidate in cron as described for the block. See drupal.stackexchange.com/questions/269913/…
    – 4uk4
    Jul 4, 2022 at 7:18

1 Answer 1

1

You could render the view isolated from the page content so that the cache data of the view doesn't bubble up.

For example in a block:

  public function build() {
    $view = Views::getView('my_view');
    $view_build = $view->buildRenderable('block_1');
    $view_rendered = \Drupal::service('renderer')->renderPlain($view_build);
    $build = [
      '#markup' => $view_rendered,
      '#cache' => [
        'tags' => ['custom_cache_tag'],
      ],
    ];
    return $build;
  }

Then the block is served from cache until you invalidate the custom cache tag:

Cache::invalidateTags(['custom_cache_tag']);

For this you could use a QueueWorker, which you add to the queue when nodes are submitted. This queue worker could then, after invalidating the tag, trigger an anonymous request to rebuild the cached block.

Only one of many possible ideas. A universal solution would be a service which caches the rendered view markup on its own, which gives you more control to serve the invalidated content while the updated view is being rebuilt.

1
  • Good idea! Regarding "Only one of many possible ideas", feel free to elaborate :) Jun 30, 2022 at 10:07

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.