Problem/Motivation

Blocked on #2450993: Rendered Cache Metadata created during the main controller request gets lost.

#2450993: Rendered Cache Metadata created during the main controller request gets lost reduces/removes all risks/implications of losing bubbleable metadata.

Proposed resolution

As a next step, we should remove the $is_root_call parameter and move the root call-specific logic out of ::render() and into ::renderRoot().

This in turn allows us to start reducing the Renderers reliance on the static $contextCollection variable, which currently prevents at least some async rendering implementations in core.

Remaining tasks

To fully enable fibers to suspend during rendering we also need #3518179: Renderer::executeInRenderContext() needs to handle nested calls and suspended fibers.

User interface changes

None.

API changes

TBD

Data model changes

None.

CommentFileSizeAuthor
#1 2511330-1.patch7.7 KBwim leers

Issue fork drupal-2511330

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

wim leers’s picture

Issue tags: +DX (Developer Experience)
StatusFileSize
new7.7 KB

This is a rough initial patch, built on top of #2450993-92: Rendered Cache Metadata created during the main controller request gets lost. This issue is postponed until that one lands.

wim leers’s picture

Status: Postponed » Needs review

This was actually unblocked a long time ago. But will need work.

Status: Needs review » Needs work

The last submitted patch, 1: 2511330-1.patch, failed testing.

fabianx’s picture

https://gist.github.com/LionsAd/cbf84e5e70b05c1ca11e is a different approach to do the same, but keeps BC.

( Need to ignore the change for #cache though as that was needed for something else.)

wim leers’s picture

I think this will need to wait until D9 now?

fabianx’s picture

Not really, my patch keeps BC so can go in whenever.

wim leers’s picture

Ok. Can you post your patch here?

fabianx’s picture

Title: Remove RendererInterface::render()'s sole $is_root_call parameter » Deprecate RendererInterface::render()'s sole $is_root_call parameter
wim leers’s picture

Assigned: Unassigned » fabianx

Per #6 + #7.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

catch’s picture

Just ran into this exception and found the @todo via #3496369: Multiple load path aliases without the preload cache and #3437499: Use placeholdering for more blocks - if you combine the two MRs from those issues and don't have bigpipe installed, you get the exception on various pages.

catch’s picture

Assigned: fabianx » Unassigned
Status: Needs work » Needs review

Converted Fabianx's patch to an MR and dealt with conflicts/cs issues.

catch’s picture

Status: Needs review » Needs work

Lots of failures. Might be worth moving Wim's patch to a second MR and see where we land with that - looks like bc could be added quite straightforwardly to Wim's approach.

catch’s picture

OK after fixing the unit tests in Wim's approach I realised the bug in Fabian's approach, so we've now got green MRs for both.

However, this is an important improvement from Fabian's:

   $child_element = &$elements[$key];
        if (isset($child_element['#cache']['keys'])) {
          $new_context = new RenderContext();
          $elements['#children'] .= $this->executeInRenderContext($new_context, function () use (&$child_element, $new_context) {
            return $this->doRender($child_element, $new_context);
          });
          // @todo This should not be necessary.
          if (!$new_context->isEmpty()) {
            $frame = $context->pop()->merge($new_context->pop());
            $context->push($frame);
          }
        }
        else {
          $elements['#children'] .= $this->doRender($elements[$key], $context);
        }
      }

e.g. when rendering children, we no longer rely on the global render context state but or even a class property, but pass the context into the method.

I think that this will either solve, or approach solving, the issues I'm running into on #3496369: Multiple load path aliases without the preload cache (where we enter and leave different rendering contexts).

catch changed the visibility of the branch 2511330-alternate-approach to hidden.

catch’s picture

OK #28 was premature but now it's green.

catch’s picture

Status: Needs work » Needs review
Issue tags: +Performance

I think the next step here is #3518179: Renderer::executeInRenderContext() needs to handle nested calls and suspended fibers but that will require interface changes to add the parameter to a couple of methods and maybe more things, so one step at a time.

#3516034: Add cacheable metadata to SelectInterface and entity QueryInterface objects is closely related too.

catch’s picture

Issue summary: View changes
catch’s picture

Category: Task » Bug report

Moving this to a bug report, it wasn't a bug as such when it was originally added to core, more of a 'limitation', but now we're using fibers for placeholder rendering, if code actually fiber suspends a decent amount, which is done in #3496369: Multiple load path aliases without the preload cache, everything explodes on cache misses.

The problem was (completely) missed in #3377570: Add PHP Fibers support to BigPipe, but this pre-existing issue solves it, alongside #3518179: Renderer::executeInRenderContext() needs to handle nested calls and suspended fibers which I just opened this week as a follow-up to this issue. The combination of the two allows that path alias issue to pass nearly all tests, but anything that uses fiber suspend in multiple placeholders will trigger the same exception at the moment.

There's very good existing test coverage of this, as shown by the several commits on both MRs here tracking down and fixing various test failures. I don't think we need explicit test coverage of the fiber suspend issue yet, it could possibly be added in #3518179: Renderer::executeInRenderContext() needs to handle nested calls and suspended fibers but not here because as soon as you fix this issue you run into that one, keeping separate for ease of review since neither are simple and they don't conflict.

catch’s picture

Issue summary: View changes
catch’s picture

andypost’s picture

Status: Needs review » Needs work

As I get it just need deprecation test

catch’s picture

Status: Needs work » Needs review

I don't think this needs a deprecation test - the deprecation path is only the trigger_error() and one line method call, no actual bc layer to test. Moving back to needs review.

godotislate’s picture

Status: Needs review » Needs work

Some comments on MR 10795.

catch’s picture

Status: Needs work » Needs review

Thanks for looking, think I resolved all of those.

godotislate’s picture

My mistake about the use Drupal\Core\Render\RenderContext; suggestion. It's in the same namespace, so it was unnecessary and flagged by PHPCS.

Also looks like phpstan baseline needs regenerating.

Added a couple comments on the typehints too.

catch’s picture

Argh I spotted the RenderContext thing after commit and before push, but failed to commit the change.

Pushed a commit for that and the other couple of comments. I think the phpstan complaint was real. Should be back to green.

godotislate’s picture

Status: Needs review » Reviewed & tested by the community

lgtm

larowlan’s picture

Status: Reviewed & tested by the community » Needs review

Left some questions on the MR

larowlan’s picture

Status: Needs review » Reviewed & tested by the community

Putting back to RTBC because all the changes from my last review where I changed the status were either trivial or reverted.
I manually confirmed we still have the bubbling check from the other point.

Given the changes here would have been fine for catch to self RTBC I think it is OK for me to commit this still.

larowlan’s picture

Status: Reviewed & tested by the community » Fixed

Committed to 11.x - thanks!
Published the change notice.

  • larowlan committed 5f80b431 on 11.x
    Issue #2511330 by catch, wim leers, larowlan, godotislate, fabianx:...
catch’s picture

kristiaanvandeneynde’s picture

I noticed the docs in doRender() were not adjusted:

     // Set the bubbleable rendering metadata that has configurable defaults, if:
     // - this is the root call, to ensure that the final render array definitely
     //   has these configurable defaults, even when no subtree is render cached.
     // - this is a render cacheable subtree, to ensure that the cached data has
     //   the configurable defaults (which may affect the ID and invalidation).
-    if ($is_root_call || isset($elements['#cache']['keys'])) {
+    if (isset($elements['#cache']['keys'])) {

They still mention that doRender() can be the root call, and from the MR it seems that doRender() should no longer be concerned with any of that. Tackle this in a tiny follow-up?

larowlan’s picture

Yes please to tiny follow up 🙏

kristiaanvandeneynde’s picture

larowlan’s picture

Thanks

berdir’s picture

The array type added here cases a fatal error for us, caused by template_preprocess_node():

$variables['date'] = \Drupal::service('renderer')->render($variables['elements']['created']);

created is null, and while it shouldn't call it then, this seems like a BC break that shouldn't be done like this or then the render () method should guard against that?

Follow-up to remove that?

berdir’s picture

catch’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.