Problem/Motivation
Every piece of content in the entire pager sequence is added to every piece of content as a cache tag (for example node:1, node:2, node:3 etc are all added to node 9,999 if you had a site with thousands of articles using entity pager.
Steps to reproduce
Set up module for a bundle of an entity type that has thousands of entities, say article nodes.
Enable header debugging (set http.response.debug_cacheability_headers: true and look at the X-Drupal-Cache-Tags header on an article node.
In the coming Drupal 11.4 you will be able to see them. In Drupal 11.3 you will almost certainly get a 500 error due to the header being too large.
Proposed resolution
Really, it should only invalidate the immediately preceding and immediately following entities, if that is all that is configured to show.
See approach being discussed in similar module #3417653: Improve cacheability metadata (which i am going back to after switching to Entity Pager some five years ago!)
Comments
Comment #2
joachim commentedThanks for reporting this.
> Really, it should only invalidate the immediately preceding and immediately following entities, if that is all that is configured to show.
That's not the right fix, unfortunately. If only it were that simple!
Suppose I made a pager view which orders nodes by their 'floopiness' integer field, and I have nodes with these values:
A: 1
B: 2
C: 10
Node B is between A and C, so you might only think it needs to have cache tags for A and C. But now I create node D with a value of 3! The pager shown on nodes B and C needs to be invalidated.
The only way to do this is to add the node_list (generically, the list cache tag).
In fact, that's a second bug: currently with the single node cache tags, B and C's pagers won't be invalidated.
(If we had #3279764: Segmented ENTITY_TYPE_list:* cache tags, we could have a setting where you can be more specific.)
Although -- I am not seeing where these cache tags are being added in the module's code. Are you sure it's coming from Entity Pager and not from Views?
Comment #3
kgertzHi both,
I ran into this exact issue ("Premature end of script headers" / HTTP status 500) on a site with ~538 news nodes and I guess the source is views core, just triggered by entity_pager's usage pattern:
in views,
StylePluginBase::renderFields()loops over every result row and calls$renderer->render($data)for each one. Inside that render,EntityFieldRenderer::render()does:$build[$row_id]['#access'] = $entity->access('view', NULL, TRUE);The
TRUEargument returns a cacheableAccessResultobject rather than a plain boolean.NodeAccessControlHandlerreturns anAccessResultAllowedcarryingnode:NNNas a cache tag. Drupal'sRenderer::doRender()then automatically bubbles thatAccessResult's cacheability into the activeBubbleableMetadatacontext, independently of anything#cache['tags']controls.This fires once per row, producing one
node:Xtag per entity in the result set, all accumulated in the render context before the view output is assembled.I think I could fix that with two things (at least in my case):
1) A custom views cache plugin overriding
getRowCacheTags()to return['node_list']instead of$row->_entity->getCacheTags().node_listis then invalidated on any node create, update, or delete2) Fields in the
entity_pagerview must be removed entirely. Even with the custom cache plugin correctly returning['node_list']fromgetRowCacheTags(), as long as any fields exist in the view,renderFields()still runs, still calls$renderer->render()per row, andEntityFieldRendererstill sets#accessas a cacheableAccessResult, bubblingnode:Xtags right back in throughBubbleableMetadata, bypassing the cache plugin.perhaps
entity_pagercould ship its own views cache plugin (implementing thenode_listapproach above) and either document that fields should not be added to entity_pager displays, or overriderenderFields()in the style plugin to skip field rendering entirely when the display uses entity_pager, since that output is never displayed anyway?Comment #4
joachim commented> in views, StylePluginBase::renderFields() loops over every result row and calls $renderer->render($data) for each one
Thanks for figuring it out! That's very helpful.
> Fields in the entity_pager view must be removed entirely
I have considered this: see #3594033: set style to not allow fields