Performance issue caused by rendering in access check

Created on 26 February 2025, 14 days ago

Problem/Motivation

In ๐Ÿ› Module causes double rendering of blocks just to check access Fixed the block access callback was removed as rendering twice was expensive.

In ๐Ÿ› Menu block renders when tree is empty as of 8.x-1.8 [regression] RTBC this was added back with a build cache - but this does not solve the issue and reintroduces the performance problem.

I do not think trying to introduce an additional cache here is correct.

A simplified version of what is happening when a request is handled:

  • BlockPageVariant determines what blocks are visible on the page - it does this by calling the block repositories getVisibleBlocksPerRegion method.
  • This method checks the block access - if TRUE then the block is added to the render array
  • At this point the view builder is adding the cache metadata, the build method itself is not called yet and a lazy builder is specified.
  • The block is then only rendered if a cache hit is not found

This means that access is being checked even when we have a cached block that doesn't get rendered. I observed this as a performance impact on search results as all the combinations of query params mean we have low cache hit rate for the page, but the menu block build itself is cached as the active trail is the same. On these pages the access check is called and we loose the cache benefits of the block.

Proposed resolution

Revert ๐Ÿ› Module causes double rendering of blocks just to check access Fixed

Identify the point in the build method where items should be checked and return an empty array there instead.

๐Ÿ› Bug report
Status

Active

Version

1.0

Component

Code

Created by

๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand ericgsmith

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @ericgsmith
  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand ericgsmith
  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand ericgsmith
  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand ericgsmith
  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand ericgsmith

    I see there was a feature added with some config for display_empty which makes this harder to revert.

    We can at least change the order here so build is only called if needed - but that will still leave the issue there for anybody with display_empty FALSE.

    Honestly I'm confused to how the block is visible when empty - I need some steps to reproduce because when there is no active child and the block returns an empty array nothing is rendered for me. Either way, if this logic is needed it should be moved out of an access check and into the build method.

  • Pipeline finished with Success
    14 days ago
    Total: 206s
    #434327
  • Pipeline finished with Failed
    14 days ago
    Total: 183s
    #434969
  • Pipeline finished with Failed
    14 days ago
    Total: 181s
    #434977
  • Pipeline finished with Success
    14 days ago
    Total: 237s
    #434980
  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand ericgsmith

    Setting MR to ready.

    I've captured where I believe the display empty bug is - in that if the tree is empty a render array is being returned. Now if display_empty is false it just returns empty here.

    There are a couple of existing empty array return points in build that I believe are not compatible with the display empty option - this likely needs further testing but that is not the point of this issue, this is to remove the rendering in the access check.

    The test passes on the MR and the test only changes pass - so I believe I have not reverted the empty behaviour intent here - but it probably needs more testing from people who previously needed such behaviour.

  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand ericgsmith

    I'll note that returning empty did not work previously for some people - https://www.drupal.org/project/menu_block/issues/3271218#comment-14499696 ๐Ÿ› Menu block renders when tree is empty as of 8.x-1.8 [regression] RTBC

    But I don't know the steps to reproduce that since it worked for others, if we can get conclusive steps to reproduce I have time to write a test for it.

  • Pipeline finished with Success
    13 days ago
    Total: 194s
    #435109
  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand ericgsmith
  • ๐Ÿ‡จ๐Ÿ‡ฆCanada joelpittet Vancouver

    Thanks for taking this on, I know for performance itโ€™s nice to back the claim up with hard data, have you ran xhprof or did something point to this as a problem?

    Iโ€™ve wrote my fair share of micro-optimization patches in my day;)

  • ๐Ÿ‡ณ๐Ÿ‡ฟNew Zealand ericgsmith

    Yes - I noticed this while investigating the general performance of search pages on a site with a very large menu.

    A few factors on the site lead it to be quite noticeable - which other sites may be susceptible to. Firstly since menu block hides the system block when adding blocks, we've ended up using menu block for all menus - which includes the very large main menu block. In addition to this, there were additional menu blocks for the footer menu, header menu and sidebar navigation block (which is also large as the search page in question is within a sub section of the site). All up that means a lot access checks for the menu. (It turns out, we aren't event using any of the features of menu block for the main menu - so editing the config to us the system block is also a solution for us). I guess because menu block hides the system block, many other sites may be using menu block for their primary navigation block.

    Using php-spx it showed that it was using around 200 -> 250ms in the menu block block access method - so for us not a micro optimisation, this is a big chunk of the request. Again that is in the context of 5 menu blocks and a large menu - not all sites will have this issue.

    Both the patch and the approach of changing to config to use system menu blocks improved page speeds by around .3s where the page is unached but the block cache is used (and no noticeable change in response time for when the block is uncached). There is a benefit of lower memory use as well given the in memory build cache is removed.

    I don't think that time will be applicable for all sites, and I haven't profiled on a clean install - but for me it shows enough that its important to fix - and given the performance issue was already previously raised it will be beneficial for all.

    My concern really is only that the people reported the previous patch in the related issue didn't work for them.

    If we absolutely need to keep the option of using block access for this, I think the 'display_empty' behaviour should be changed so we have to explicitly opt in to the access check.

  • ๐Ÿ‡จ๐Ÿ‡ฆCanada joelpittet Vancouver

    Iโ€™ll also be working on a large menu for an intranet soon, so Iโ€™ll definitely test this out. Thanks for the detailed response!

    Ideally, we can find a solution that makes everyone happy. If thereโ€™s a relatively small change (like the one you made by switching conditions), those are easy wins, though they might not fully align with what youโ€™re aiming for.

  • Pipeline finished with Success
    8 days ago
    Total: 265s
    #439259
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States joegraduate Arizona, USA

    Adding latest MR diff as static patch file for composer.

  • ๐Ÿ‡จ๐Ÿ‡ฆCanada joelpittet Vancouver
Production build 0.71.5 2024