Problem/Motivation
Setting this to major (critical?) since this can break contrib, with no easy workaround.
When a service implements \Drupal\Core\DestructableInterface, the service is registered to the kernel.destructable_services container parameter.
However if any of these services are decorated, then you'll get errors like:
Fatal error: Uncaught Error: Call to undefined method Drupal\hux\HuxModuleHandler::destruct() in /data/app/core/lib/Drupal/Core/DrupalKernel.php:687
This error here happens since modules like Hux, Hook Event Dispatcher, Domain, and others, decorate ModuleHandler.
However this issue isnt confined to ModuleHandler, but any service that implements \Drupal\Core\DestructableInterface, where the main interface (e.g.\Drupal\Core\Extension\ModuleHandlerInterface) doesnt also implement DestructableInterface.
Steps to reproduce
- Create a service implementing DestructableInterface
- Create a service decorating the above service. Where the this service does not implement DestructableInterface.
- Clear container cache; crash.
Proposed resolution
Track and execute destruct only on the original (inner) services???
Remaining tasks
Discuss, implement, fix
User interface changes
Nil
API changes
Probably limited to core behaviour only.
Data model changes
Nil
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #29 | 3441010-nr-bot.txt | 90 bytes | needs-review-queue-bot |
| #26 | 3441010-nr-bot.txt | 90 bytes | needs-review-queue-bot |
| #20 | 3441010-nr-bot.txt | 90 bytes | needs-review-queue-bot |
| #8 | hux-destruct-3441010.patch | 2.1 KB | larowlan |
Issue fork drupal-3441010
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
Comment #2
dpiComment #3
dpiAn un-fun way to solve this, which we should avoid, is also: adding the making the service interface (such as
ModuleHandlerInterfaceimplementDestructableInterface.Comment #4
dpiIf we determine a service must now implement separate interfaces, then I think #3412556: Allow needs_destruction services to run on page cache hits needs a changelog entry.
In the case of
\Drupal\Core\Extension\ModuleHandler::writeCache, should this method be deprecated and removed from the interface?Comment #5
catchShould we be doing an instanceof check for destructable interface in DrupalKernel::terminate()?
And/or should hux be removing the terminate tag from the service definition?
Comment #6
dpi@catch I'm wondering if theres a way to just call destruct on the original.
Thinking of Symfony concepts when utilising decorators.
If a service has `calls` applied to it, it doesnt matter if it decorated or not, the calls are always applied to the original/inner service, not the outermost service.
E.g, given:
At no point will an attempt to call dpi.deco::foo() happen.
Comment #7
larowlanAny reason hux can't implement destructable and just call the inner method from its implementation?
Comment #8
larowlanSomething like this for hux (1.3.x branch) seems to work
Comment #9
catch#7 was my first thought, but it would probably be good to do something in core so it doesn't crash, even if that's an instanceof check before calling the destruct method.
Comment #12
longwaveI think the MR will work but the services are meant to be destructible for a reason, maybe we should issue a warning/deprecation when we find a non DestructableInterface service so downstream users are notified?
Comment #13
catchDoh it's because the classes are in the same namespace so we don't need a use statement at all. Thanks @longwave.
Pushed up a second branch with another idea which I think is closer to what @dpi is asking for - if we autoconfigure the tag for services with the interface, then decorating services won't get the tag, but inner services still would. However, it's not actually working. We do have one example of autoconfiguring tags in core, but I've never tried it before, hopefully a similarly silly mistake.
Comment #15
catchI had a play with
and didn't get anywhere. Maybe every services.yml needs to specify autoconfigure: true for even this to work? I guess we could do that but it feels like a bigger change than the scope here.
Instead, I'm iterating over the service definitions where we collect the tagged services, and adding the tag to them there, this seems to work (at least the one test I'm running locally works, as did some manual testing). This was @longwave's suggestion in slack as one of several possible options.
Maybe we can do this to un-fatal things then open a follow-up to use autoconfigure more?
Comment #16
longwave#15 strikes me as being the same root cause as #3446026: Adding media library openers use autoconfigure and tags in 10.3.x has BC consequences so I think worth seeing if we can solve both problems with one solution.
Comment #17
catchI think we might need to just do the quick fix here tbh. Bumping priority since a couple more contrib have reported this now. https://drupal.slack.com/archives/C1BMUQ9U6/p1716826820826669
Comment #18
dqdThanks at all tracking this so quick and raising prio. Contacted some bigger contrib checking against 10.3 beta to be aware of it. Rephrase my question
@catch@longwave:Is your attempt (green MR) applyable to at least get rid of WSOD as a dirty fix while working on a final solution?@catch: How to help here. Any steps where others can chime in?
Comment #19
dqdAdded Domain to summary as a big contrib affected by this, since this will not only break one but all sites (domains) in the project.
Comment #20
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #21
dqdremoved (wrong issue)
Comment #22
znerol commentedI'd suggest to revert #3412556: Allow needs_destruction services to run on page cache hits. The justification for that change isn't that convincing, and the risk assessment expressed in the CR clearly missed the effects on contrib.
Comment #23
catchThis looks completely unrelated.
@znerol that might help with the 2-3 modules affected here, but it won't with similar issues like #3446026: Adding media library openers use autoconfigure and tags in 10.3.x has BC consequences.
Comment #24
dqd@catch: Yes, it is... wrong issue, sry (mixed tabs, removed comment to prevent confusion)
Comment #25
agentrickardYes, the domain issue here is actually https://www.drupal.org/node/3425054 -- though we still need to check these decorations:
Those should be two issues in the Domain queue.
Comment #26
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #28
catchHiding the autoconfigure branch.
Comment #29
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #30
el7cosmosIn the case of module handler, even if without changes from #3412556: Allow needs_destruction services to run on page cache hits, decorators that don't implement
DestructableInterfacewill also fail in 10.2 if we apply #3436599: Replace RequestCloseSubscriber with needs_destruction tag on ModuleHandler.this just because the call changed from
writeCachewhich declared inModuleHandlerInterfacetodestructwhich is new implementation.As for #3412556: Allow needs_destruction services to run on page cache hits, I don't think we can access decorated/original service from
DrupalKernel, so even if we register the original service inkernel.destructable_services(eghux.module_handler.inner) we won't be able to get it from the Kernel with$this->container->get('hux.module_handler.inner').Perhaps, instead of a parameter we can create a service that can receive the original service as the argument, but that will initialize the instance and defeat the purpose of
$this->container->initialized($id).I can't see any other solution than:
DestructableInterfacefrom the service's interface, not implementation, this will enforce decorators to implement that also.DestructableInterface, but the container will crash if it is not.Comment #31
longwaveDiscussed with @alexpott at Dev Days Burgas.
We agreed that option 1 from #30 is the correct thing to do here. Under the interfaces BC policy we are allowed to add methods to interfaces in minors where there is a 1-1 relationship with an implementation, which there is here with ModuleHandler.
We also think that this can be implemented in a 10.3.x patch release, given it is no more broken than it is already if someone is replacing the implementation of ModuleHandler with an alternative version that only implements ModuleHandlerInterface without implementing DestructableInterface as well.
Comment #34
longwaveComment #35
geek-merlinRan into this when i had a site with hux:1.4 on core:10.3. Updating to hux:1.5 fixes the site problem.
As for MR !8558:
I reviewed the code and can confirm that it trivially implements the #30.1 proposal (single extended interface).
Requiring a test for this imho is only boilerplate.
Behavior-wise: I can confirm that adding this patch changed the core:10.3+hux:1.4 error like below:
Before:
After:
Thus RTBC-ing.
Comment #36
geek-merlinFYI but out of scope here: For my own needs i use Composable Inheritance to avoid (amongst others) this kind of pain on highly self-coupled classes that are a pain to decorate but nice to inherit.
Comment #41
alexpottDiscussed with @catch and @longwave - we agreed to make this change because whilst it does not fix the issue it is a better break and help module maintainers fix it quickly.
Committed and pushed e82372379d to 11.x and 1dd699f07a to 11.0.x and b8241d8c6d to 10.4.x and d0f39b40d2 to 10.3.x. Thanks!