Block access is checked even if the block's region is never rendered

Created on 13 July 2023, almost 2 years ago

Problem/Motivation

BlockPageVariant::build() calls BlockRepository::getVisibleBlocksPerRegion() and this method calls the access function of every block in each region, even if a region is never used in the page.

Steps to reproduce

  1. Create a block that has slow access function or one that returns a short max-age.
  2. Place this block in a region without any condition.
  3. Don't render this region in page.html.twig.
  4. The cache parameters from the block access result bubble to the page, even if the region is not displayed.

We noticed this because it creates problems with the blockgroup module (because it implements block groups as regions): πŸ› Block access is checked even if block is inside a group that is not displayed Active

Proposed resolution

I guess instead of checking every block access upfront, they could be checked lazily when their parent region is rendered.

πŸ› Bug report
Status

Active

Version

10.1 ✨

Component
BlockΒ  β†’

Last updated 10 days ago

Created by

πŸ‡«πŸ‡·France prudloff Lille

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

Merge Requests

Comments & Activities

  • Issue created by @prudloff
  • last update almost 2 years ago
    29,442 pass, 1 fail
  • πŸ‡«πŸ‡·France prudloff Lille

    I just noticed that BlockRepository::getVisibleBlocksPerRegion() checks the access on every block from every region and then only keeps blocks from regions returned by ActiveTheme::getRegions(), so some of these access checks are called for nothing.

    I opened a MR that makes it check only blocks from regions returned by ActiveTheme::getRegions().
    This might fix πŸ› Block access is checked even if block is inside a group that is not displayed Active but not the issue with theme regions that are not rendered.

  • last update almost 2 years ago
    29,446 pass
  • Pipeline finished with Success
    about 2 months ago
    Total: 445s
    #436776
  • Pipeline finished with Success
    about 2 months ago
    #436780
  • Status changed to Needs review about 2 months ago
  • πŸ‡«πŸ‡·France prudloff Lille

    Added some unit tests to show the problem.

  • πŸ‡¨πŸ‡­Switzerland berdir Switzerland

    The issue summary says:

    > Don't render this region in page.html.twig.

    But then the implementation uses $activeTheme->getRegions(). That's not the same thing. getRegions() isn't dynamic. I'm not clear how it would even be possible to have a block defined for a region that's not in there?

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    @prudloff mind updating the summary some please.

  • πŸ‡«πŸ‡·France prudloff Lille

    I originally opened the issue because we noticed that access to some blocks was checked even if they were in a region that's never really displayed. (In our case regions created by the blockgroup module.)
    My first approach was to try to check access only if the region is rendered.

    Then I noticed in #2 that regions created by blockgroup were not return by $active_theme->getRegions().
    So I thought that would be a simpler way to exclude them.

    But I just checked again and I think I was misled because when you create a new region in blockgroup, at first it appears on /admin/structure/block but not in $active_theme->getRegions().
    But if you clear caches, it starts appearing in $active_theme->getRegions().
    So my solution is not useful.

  • πŸ‡«πŸ‡·France prudloff Lille

    prudloff β†’ changed the visibility of the branch 3374446-block-access-is to hidden.

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Thank you for taking a look! Still an issue though?

  • πŸ‡«πŸ‡·France prudloff Lille

    Yes, the issue summary is still correct.

  • πŸ‡¨πŸ‡­Switzerland berdir Switzerland

    It may be correct, but I'm not sure it's fixable. We can't know if there's going to be some dynamic preprocess/twig logic deciding not to print regions. There is no concept for regions being dynamic. And checking access likely still faster than preparing the block that then won't be used, especially with all the stuff around placeholdering and so on.

    There are open issues around improving block access caching, might make more sense to focus on that and start caching accessible/non-accessible information if it's well cacheable.

  • πŸ‡«πŸ‡·France prudloff Lille

    I agree this would hard to fix without changing the way regions work.

    Our main concern is this scenario :
    - We have a region that is not displayed on every page.
    - This region contains a block and the block's access method returns an access result with a low max age.
    - Every page inherits this low max age even if the region is not displayed.

    Our current workaround is to add a condition on the block itself that duplicates the logic that displays the region. (I think block access methods are not called if their condition is false.)
    But this can be tedious if the region contains a lot of blocks.

    Should we close this as wontfix since we don't really have a solution with the current region system?

  • πŸ‡¨πŸ‡­Switzerland berdir Switzerland

    Did you consider doing the thing that depends on age/time while building the block instead of access? so you allow access, but you return an empty array, that should result in displaying nothing, see \Drupal\block\BlockViewBuilder::preRender.

    And you could further combine that into forcing a lazy builder, see πŸ“Œ Create placeholders for more things Active and combined with recent lazy builder/render cache optimizations, that should then be pretty efficiently cache your block separately from dynamic page cache. We have auto-placeholder cache contexts, we could possibly also have auto-placeholder max-age, so if things are for example cacheable for less than 600s, we automatically placeholder them if possible.

    But yes, I'd say this is a won't fix, see #2479459: BlockRepository::getVisibleBlocksPerRegion() does an uncached entity query on every request β†’ for a related discussion although that one is more about the entity query than access.

  • πŸ‡«πŸ‡·France prudloff Lille

    Did you consider doing the thing that depends on age/time while building the block instead of access?

    Yes, we do that for some custom blocks but it is not always possible for more complex contrib blocks, for example πŸ› Facet block adds view max age on every page Active

    Marking as wontfix then.

Production build 0.71.5 2024