Problem/Motivation
After the fix in #3410022: Regression from #3295790 content-length header set earlier than expected, running database updates via drush updb throws an uncaught exception. In #3412160: Uncaught exception thrown when running database updates via drush we worked around this by removing final. This issue is for adding
final<code> back.
The underlying issue is that lazy Symfony services do not support <code>final classes, but this can be worked around with interface proxying:
https://symfony.com/doc/6.4/service_container/lazy_services.html#interface-proxifying
If there is more than one service tagged 'http_middleware' and at least one that is a responder, Drupal\Core\DependencyInjection\Compiler\StackedKernelPass::process() sets all those middleware services as lazy, other than the first responder.
The issue only seems to surface in Drupal (as observed so far) when the kernel's container is an instance of Symfony\Component\DependencyInjection\ContainerBuilder. The Drupal\Core\Update\UpdateKernel has its container set to an instance of ContainerBuilder, and the exception is thrown in the kernel terminate() method, when the call to ::getHttpKernel() leads to $this->container->get('http_kernel'), and as the decorated service is instantiated, the lazy middleware services are proxied, leading to an exception on final classes. Since this exception is thrown during the terminate phase, the exception is not displayed in browser when running updates via browser at update.php. The exception is logged, though. when running updates via drush, the exception stops the command from completing.
Proposed resolution
- Add back "final" to Drupal\big_pipe\StackMiddleware\ContentLength
- Add 'proxy' tags to http_middleware services set to lazy in Drupal\Core\DependencyInjection\Compiler\StackedKernelPass with the Symfony\Component\HttpKernel\HttpKernelInterface (and possibly Symfony\Component\HttpKernel\TerminableInterface) interfaces
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
Issue fork drupal-3412168
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:
- 3412168-add-back-final
changes, plain diff MR !6017
Comments
Comment #2
godotislateThis might not be a drush issue? https://github.com/drush-ops/drush/issues/5848#issuecomment-1876021392
From this part of the exception thrown documented in #3412160: Uncaught exception thrown when running database updates via drush,
Looked at Symfony docs for Lazy Services: https://symfony.com/doc/6.4/service_container/lazy_services.html, and saw this:
Suggestion there is to use interface proxying:
Comment #4
godotislateOpened MR 6017 as experiment to use interface proxying per previous comment in the service declaration. Ran
drush updbwith this change and saw saw no exceptions thrown and updates ran successfully.Not sure how to reproduce the exception otherwise, so leaving it here for now.
Comment #5
godotislateTurns out it's not a Drush-specific problem, and the error was not obvious on update.php because the exception was thrown during kernel->terminate() call after page was already sent to browser. Exception does show up in the log.
Updated IS. Updated MR with proposed approach and added a unit test.
Comment #6
smustgrave commentedRan the test-only job
Issue summary proposed solution match the fix.
Left a comment but that's just a curiosity and not a blocker if anyone see's that thread.
Change LGTM!
Comment #7
longwaveTiny whitespace nitpick otherwise this looks good to me.
Comment #9
godotislateFixed whitespace. Moving back to RTBC since that was the only thing.
Comment #10
longwaveDecided not to backport as this isn't critical, if someone is doing something strange in 10.2 we won't break their code but they will have to fix for 10.3.
Committed c10494d and pushed to 11.x. Thanks!