TL;DR

If a module provides a subscriber for a kernel event, for example (\Symfony\Component\HttpKernel\KernelEvents::RESPONSE), and it gets uninstalled on the UI then the event dispatcher service still calls its event subscriber that could lead to errors.

Problem

Our module provides an MY_ENTITY_TYPE entity type and it has a KernelEvents::RESPONSE subscriber, my_module.event_subscriber.response. The event subscriber retrieves the entity storage of the MY_ENTITY_TYPE in its constructor. What happens when the module gets uninstalled on the UI? The \Drupal\Core\Extension\ModuleInstaller::uninstall() does a bunch of things, but most notably:
* uninstalls the MY_ENTITY_TYPE entity type
* calls the $this->updateKernel($module_filenames); - before that the my_module.event_subscriber.response service is still registered. If you run $container->get('event_dispatcher') at this point and check the registered listeners with xDebug you should see the my_module.event_subscriber.response is not registered anymore.
* after the ModuleInstaller::uninstall() finished the module is uninstalled.
* the reponse for the request is also ready so the HTTP Kernel triggers the KernelEvents::RESPONSE event.
* (surprise) the called instance of the event_dispatcher service in that context still contains the my_module.event_subscriber.response event subscriber as a registered listener so it gets called
* and the request silently fails with an exception in \Symfony\Component\HttpKernel\HttpKernel::handleException() because as I wrote the "The event subscriber retrieves the entity storage of the MY_ENTITY_TYPE in its constructor." but the entity type is not registered anymore.

Proposed solution

After a module gets uninstalled Drupal core should not call its event subscriber (including kernel events). At least, I do not see any use case why an uninstalled module's event subscriber should be called after it has been uninstalled within the same page request.

CommentFileSizeAuthor
#38 uninstalled-module-kernel-response-listener-fix-3056604-37-8.8.x.patch14.34 KBmxr576
#37 interdiff_33_37.txt698 bytesmxr576
#37 uninstalled-module-kernel-response-listener-fix-3056604-37.patch14.31 KBmxr576
#34 interdiff_29_33.txt693 bytesmxr576
#34 uninstalled-module-kernel-response-listener-fix-3056604-33.patch14.37 KBmxr576
#33 interdiff_23_33.txt1.07 KBmxr576
#29 interdiff_25_29.txt1.58 KBmxr576
#29 interdiff_23_29.txt895 bytesmxr576
#29 uninstalled-module-kernel-response-listener-fix-3056604-29.patch14.18 KBmxr576
#25 interdiff_23_25.txt948 bytesmxr576
#25 uninstalled-module-kernel-response-listener-fix-3056604-25.patch14.62 KBmxr576
#24 screeshot-2019-05-27-16-54-06.png189.97 KBmxr576
#23 uninstalled-module-kernel-response-listener-fix-3056604-23.patch13.84 KBmxr576
#23 interdiff_18_23.txt1012 bytesmxr576
#19 interdiff_16_18.txt5.96 KBmxr576
#19 uninstalled-module-kernel-response-listener-fix-3056604-18.patch13.79 KBmxr576
#16 interdiff_16_before_content_translation_fix_16.txt4.44 KBmxr576
#16 interdiff_13_16.txt15.59 KBmxr576
#16 uninstalled-module-kernel-response-listener-fix-3056604-16.patch13.9 KBmxr576
#15 uninstalled-module-kernel-response-listener-fix-3056604-15_test_only.patch6.71 KBmxr576
#13 updateKernel.png111.97 KBmxr576
#13 interdiff_11_13.txt1.76 KBmxr576
#13 uninstalled-module-kernel-response-listener-fix-3056604-13.patch7.29 KBmxr576
#11 interdiff_10_11.txt2.07 KBmxr576
#11 uninstalled-module-kernel-response-listener-fix-3056604-11.patch7.08 KBmxr576
#10 uninstalled-module-kernel-response-listener-fix-3056604-10.patch7.6 KBmxr576
#6 drupal-uninstalled-module-kernel-response-listener-fix-3056604-6.patch4.09 KBmxr576
drupal-event-dispatcher-bug-poc-test.patch2.19 KBmxr576

Comments

mxr576 created an issue. See original summary.

mxr576’s picture

Thanks for the event subscriber that I added in drupal-event-dispatcher-bug-poc-test.patch the \Drupal\Tests\system\Functional\Module\UninstallTest::testUninstallPage() fails because the new event subscriber that I added gets called after the "Module test" module is uninstalled and the thrown exception causes an HTTP 500.

alexpott’s picture

Nice find. This totally makes sense. In Symfony land the codebase never changes from underneath you whereas in Drupal land we have the ability to install and uninstall module in a request. Which makes us vulnerable to bugs like this. I think this is another reason why we need to have our own event dispatcher rather then leverage Symfony's as our needs to be module installation status aware.

However one thing that's interesting is that the event dispatcher should be rebuilt on uninstall. So the question also becomes why

  • does the new event dispatcher use uninstalled module events
  • OR why does something have the old event dispatcher still hanging around
alexpott’s picture

So looking at the code it's because of

OR why does something have the old event dispatcher still hanging around

. The http_kernel service is constructed with the event dispatcher at the beginning of the request and there's no way to rebuild this because it's responsible for calling the module uninstall code itself.

mxr576’s picture

mxr576’s picture

Well, it is already late Friday here but I may have found a simple fix for the module. I am not asking a full review on this just yet, although anybody can provide feedback about the idea. I'll check this with a clear head on Monday :)

mxr576’s picture

Well, it was too good to be true...

alexpott’s picture

Ah look at that... the fail shows what we need to do! We need ModuleInstall::uninstall() command to call Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher::removeListener() on the old event dispatcher prior to rebuilding the kernel.

So maybe something like...
Get the old event dispatcher before uninstalling.

After uninstall get the list of listeners from the old service and new service and then the remove the ones that aren't there from the old service... or something like that.

mxr576’s picture

Well, I already had the failing POC test case when I created this issue, I hoped that I also have a fix now :)

After uninstall get the list of listeners from the old service and new service and then the remove the ones that aren't there from the old service...

Yeah, probably this is the next best option that I could try because as I can see there is no API that I could use to collect all services defined by the uninstalled module before it gets uninstalled. Registered services does not store a reference to the module that defines time. Assuming that all service ids contain the provider modules' names would be a bold guess.

mxr576’s picture

Status: Active » Needs review
StatusFileSize
new7.6 KB

Maybe now...

This patch verifies all event listeners not just those that listens on the KernelEvents::RESPONSE. I was not sure which event listeners should be validated and which not so I choose to verify all. This seemed the safest option.
If we do not want to validate all then probably we should add the KernelEvents::TERMINATE event to the list as well. Not sure what else could be triggered after the given state of the request.

mxr576’s picture

StatusFileSize
new7.08 KB
new2.07 KB
mxr576’s picture

Status: Needs review » Needs work

Tbc

mxr576’s picture

Status: Needs work » Needs review
StatusFileSize
new7.29 KB
new1.76 KB
new111.97 KB

\o/

Let's handle when there is no event by type in the up to date event dispatcher anymore.

Originally I fixed the doc block of the updateKernel() method. Not sure whether I can do that as part of this issue or not.

   /**
    * Updates the kernel module list.
    *
-   * @param \Drupal\Core\Extension\Extension[] $module_filenames
+   * @param string $module_filenames
    *   The list of installed modules.
    */
-  protected function updateKernel(array $module_filenames) {
+  protected function updateKernel($module_filenames) {
     // This reboots the kernel to register the module's bundle and its services
     // in the service container. The $module_filenames argument is taken over as
     // %container.modules% parameter, which is passed to a fresh ModuleHandler
@@ -589,12 +589,14 @@
     };

PHPstorm warning

alexpott’s picture

Status: Needs review » Needs work
  1. +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
    @@ -50,6 +51,13 @@ class ModuleInstaller implements ModuleInstallerInterface {
    +  private $eventDispatcher;
    

    I agree with private here because it will often end up being the wrong event dispatcher and because of this I think we need to denote this complexity in both the comments and property name. So how about $initialEventDispatcher?

  2. +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
    @@ -59,14 +67,17 @@ class ModuleInstaller implements ModuleInstallerInterface {
    +    $this->eventDispatcher = $even_dispatcher;
    

    $event_dispatcher :)

  3. +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
    @@ -460,8 +471,9 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
    +      // Update the kernel to exclude the uninstalled modules and unregister
    +      // event listeners that belonged to them.
    +      $this->updateKernelAfterUninstall($module_filenames);
    

    This makes me realise we have the problem the other way around. There's no way for a module to be subscriber to the KernelEvents::RESPONSE on the response they were installed on. Which is a bug because potentially they have code that is triggered on such a request that assumes it will be /shrug who knows?!?! Tricky. But logically I think doing the same (but adding listeners) for install makes sense.

  4. +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
    @@ -555,6 +567,46 @@ protected function updateKernel($module_filenames) {
    +    $up_to_date_listeners = \Drupal::service('event_dispatcher')->getListeners();
    

    $this->kernel->getContainer()->get('event_dispatcher') is mildly easier on the eye than \Drupal::service() because at least we're using an injected (albeit re-injected) object.

  5. +++ b/core/modules/system/tests/modules/module_test/src/EventSubscriber/ResponseSubscriber.php
    @@ -0,0 +1,56 @@
    +  /**
    +   * Throws an exception if the Module test module is uninstalled.
    +   *
    +   * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
    +   *   The event.
    +   */
    +  public function handle(FilterResponseEvent $event) {
    +    if (!$this->moduleHandler->moduleExists('module_test')) {
    +      throw new \RuntimeException('The Module test module has already uninstalled, this event should not be called.');
    +    }
    +  }
    

    Using this as a test is fragile because our only test for this is the absence of the exception being thrown. What we would be better is if this set some state and the test checks that the state is set before uninstalling the module and then the test removes the state and uninstalls the module and checks it doesn't come back. You can leave the exception in to be super sure but having a correlating positive assertion means that even if the events change and we miss this nuance we'll know if we've affected this.

mxr576’s picture

Title: Kernel event subscribers of an uninstalled module should not be called » Register/unregister event listeners provided by a module on install/uninstall
Issue tags: +module install, +drupal kernel, +HttpKernel
StatusFileSize
new6.71 KB

Thanks for the review!

1. make sense, fixed
2. ty, fixed
3. well, this also came into my mind earlier but first I wanted to solve the task at hand :)
4. fixed
5. Well, works for me, I rewrote the test to use indicator value. My usual problem with the State service that even it could be used as shared storage between $this->container and \Drupal::service() in browser tests, it has a static cache where values can stick and they can cause false-positive test failures

Updated the test only patch.

mxr576’s picture

Status: Needs work » Needs review
StatusFileSize
new13.9 KB
new15.59 KB
new4.44 KB

Updated patch with the test and fix.

Additional comment regarding the 3, point. I almost submitted the patch when the core/modules/system/tests/src/Functional/Module/InstallUninstallTest.php had started fail. It was caused by this error:

Symfony\Component\Routing\Exception\RouteNotFoundException: Route "entity.configurable_language.collection" does not exist. in Drupal\Core\Routing\RouteProvider->getRouteByName() (line 201 of core/lib/Drupal/Core/Routing/RouteProvider.php).
Drupal\Core\Routing\UrlGenerator->getRoute('entity.configurable_language.collection') (Line: 271)
Drupal\Core\Routing\UrlGenerator->generateFromRoute('entity.configurable_language.collection', Array, Array, 1) (Line: 105)
Drupal\Core\Render\MetadataBubblingUrlGenerator->generateFromRoute('entity.configurable_language.collection', Array, Array, ) (Line: 753)
Drupal\Core\Url->toString() (Line: 29)
content_translation_install()
call_user_func_array('content_translation_install', Array) (Line: 392)
Drupal\Core\Extension\ModuleHandler->invoke('content_translation', 'install') (Line: 315)

Took some time while I figured out what went wrong, but it easier if I show the diff between the submitted and the non-submitted patch.

What is the main difference? All those additional tasks that are running before new events get registered. The failure with my original changes was caused by this code because it run after events got registered:

        \Drupal::getContainer()->set('router.route_provider.old', \Drupal::service('router.route_provider'));
        \Drupal::getContainer()->set('router.route_provider', \Drupal::service('router.route_provider.lazy_builder')); 

But after I fixed this there was a new failure caused by the unregistered entitites and entity view modules.

So I think the best way is the add the event registration to the end of the install process. Also applied the same logic on the uninstall process, although that has not failed as it was implemented before. Open for ideas what should be the best place to call the event register/unregister methods if not the current ones.

alexpott’s picture

So I thought the best was is the add the event registration to the end of the install process. Also applied the same logic for the uninstall process, although that has not failed before. Open for ideas what should be the best place to call the event register/unregister methods if not the current ones.

Yeah that is a super super interesting.

One thing I've tried to do is to make the install and uninstall methods kind of mirror opposites of each other. I think the location of the install event registration feels like it is in a good position. You're events are only triggered once your module's hook_install() has fired. So I think we need to do the reverse as well - ie remove the events prior to your modules hook_uninstall() being triggered.

+++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
@@ -555,6 +573,76 @@ protected function updateKernel($module_filenames) {
+  protected function unregisterEventsAfterModuleUninstall() {

Let's use the work remove rather than unregister. Using the event dispatcher interface as inspiration. Same with the docs and variable names in the method.

mxr576’s picture

One thing I've tried to do is to make the install and uninstall methods kind of mirror opposites of each other.

Yes, this totally makes sense. How about this?

      // Clean up all entity bundles (including fields) of every entity type
      // provided by the module that is being uninstalled.
      // @todo Clean this up in https://www.drupal.org/node/2350111.
      $entity_manager = \Drupal::entityManager();
      $entity_type_bundle_info = \Drupal::service('entity_type.bundle.info');
      foreach ($entity_manager->getDefinitions() as $entity_type_id => $entity_type) {
        if ($entity_type->getProvider() == $module) {
          foreach (array_keys($entity_type_bundle_info->getBundleInfo($entity_type_id)) as $bundle) {
            \Drupal::service('entity_bundle.listener')->onBundleDelete($bundle, $entity_type_id);
          }
        }
      }

      // Remove event listeners from the initial event dispatcher that
      // belonged to the removed module.
      $this->removeEventListenersAfterModuleUninstall();

      // Allow modules to react prior to the uninstallation of a module.
      $this->moduleHandler->invokeAll('module_preuninstall', [$module]);

      // Uninstall the module.
      module_load_install($module);
      $this->moduleHandler->invoke($module, 'uninstall');

      // Remove all configuration belonging to the module.
      \Drupal::service('config.manager')->uninstall('module', $module);
Let's use the work remove rather than unregister. Using the event dispatcher interface as inspiration. Same with the docs and variable names in the method.

Also replaced "register" with "add" based on the same logic.

mxr576’s picture

mxr576’s picture

Title: Register/unregister event listeners provided by a module on install/uninstall » Add/remove event listeners provided by a module on module install/uninstall

Status: Needs review » Needs work
mxr576’s picture

Status: Needs work » Needs review
StatusFileSize
new1012 bytes
new13.84 KB

Meh, of course, it failed. Either the test case needs to be adjusted or the event listener removal must run after kernel update. I rather prefer the second option which the updated patch implements because I guess until the kernel has not updated a removed event listener, which is a service, still can be called as a service.

One possible way to adjust the test is to set an indicator value in module_test_uninstall() and use that in the ModuleInstallUninstallResponseSubscriber to set the other indicator value.

mxr576’s picture

StatusFileSize
new189.97 KB

Additional info from our module's test suite. Tests with #18 passed but with #23 failed because the dynamic route subscriber tried to rebuild module related routes when some services provided by the module has been already uninstalled.

So probably the best place to do the event subscriber removal is somewhere in-between #18 and #23.

mxr576’s picture

Well, this is getting worse and worse...

Managed to figure out why our test has failed. Even if this should ensure uninstalled entity types get _completely_ unregistered from the system but they do not. At least in this service, in the injected entity type manager's _static_ cache they still remain registered. The EntityDefinitionUpdateManager is unable to clear the static cache of a service which is running in a different "scope".

I tried out several ways to resolve this problem. Tried to inject the EntityDefinitionUpdateManager to the ModuleInstaller and use that in uninstall() instead of \Drupal::entityDefinitionUpdateManager(), etc. I also tried to run \Drupal::entityTypeManager()->clearCachedDefinitions(); before and after the updateKernel() method call in the uninstall() but it only worked this place where I left in this patch.

I am starting to feel like that it would be better to completely rewrite this service instead of trying to patch newly appearing issues. There are too many TODOs in this class already.

I guess this new issue with incomplete entity type deregistration would require a new POC test. Should it be handled in a new issue or not? It is also related to event dispatching in ModuleInstaler so it also makes sense to resolve this here.

What do you think about all of this @alexpott?

mxr576’s picture

mxr576’s picture

Tried to write a test case for the described issue in #24 #25, but I had no luck until this time. This made me think that maybe I was actually right in #23 and the event deregistration should happen in a different place in the uninstall() method. At least right now I do not see a better explanation for why our internal tests passed with #19 but failed with #23 without the change in #25.

mxr576’s picture

Additional info to #23. I can move $this->removeEventListenersAfterModuleUninstall(); below in the uninstall() method until it is above the \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions(); call our functional test passes. If I move it after the \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions(); call then our test starts failing without #25 because the plugin.cache_cleaner clears some kind of caches, probably the entity_type.manager service's cache which is tagged with plugin_manager_cache_clear.

mxr576’s picture

Next combination of change that seems to be working and somehow it still makes more sense than the fix in #25 although I am still trying to understand why this is working. Basically by moving the plugin.cache_cleaner call below the updateKernel() method call the EntityRouteProviderSubscriber still calls the uninstalled entity type's dynamic route provider, but the cache service defined by uninstalled module is still registered therefore the test does not fail like with #23: https://www.drupal.org/files/issues/2019-05-27/screeshot-2019-05-27-16-5....

catch’s picture

+++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
@@ -555,6 +573,76 @@ protected function updateKernel($module_filenames) {
+
+    // Add event listeners provided by installed modules on the
+    // initial event dispatcher which is still used by the HTTP Kernel service
+    // that handles the current request.
+    $up_to_date_event_dispatcher = $this->kernel->getContainer()->get('event_dispatcher');
+    foreach ($up_to_date_event_dispatcher->getListeners() as $event_name => $listeners) {
+      $up_to_date_event_listeners_by_event = $this->processEventListeners($listeners);
+      if (isset($old_event_listeners[$event_name])) {
+        $old_event_listeners_by_event = $this->processEventListeners($old_event_listeners[$event_name]);
+        $event_listeners_to_add = array_diff_key($up_to_date_event_listeners_by_event, $old_event_listeners_by_event);
+      }
+      else {
+        $event_listeners_to_add = $up_to_date_event_listeners_by_event;
+      }

Is it worth trying to consolidate getting the diff of event listeners into another helper method? No rule of three here, but the code is pretty much identical except for the addListener/removeListener calls.

I think this is another reason why we need to have our own event dispatcher rather then leverage Symfony's as our needs to be module installation status aware.

This once again brings up #2237831: Allow module services to specify hooks, have updated that issue.

mxr576’s picture

No rule of three here, but the code is pretty much identical except for the addListener/removeListener calls

Well, I was thinking about this too and I am still not sure whether it makes sense to extract this diff creation to a method where the method that it gets called (addListener/removeListener) would be also a parameter or an anonymous function. Maybe with this refactoring, we would just replace a small copy-paste like-ish code to something that causes bigger complexity and it is not easier to maintain.

catch’s picture

+++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
@@ -471,12 +471,12 @@
 
-      // Clear plugin manager caches.
-      \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions();
-
       // Update the kernel to exclude the uninstalled modules.
       $this->updateKernel($module_filenames);
 
+      // Clear plugin manager caches.
+      \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions();
+

On this diff, we should double check that the order hasn't changed before by looking at the order of the file. Also we should add a comment explaining that the plugin manager cache clear is explicitly after the kernel update, possibly with a @todo to a follow-up to investigate further why it's necessary.

mxr576’s picture

Also sharing a conversation between me and @catch from Slack here that relates to #32

I tried to modify Drupal core test and non-test modules to reproduce this issue, but tests always passed with #23. The last thing that I can think about that the container building handles core and contrib modules differently... but I haven't invested time to this bold theory.

catch [1 day ago]
@mxr576 there shouldn't be any difference between core and contrib modules fwiw, the only issue maybe is the order in which they get discovered.
@mxr576 having said that I can't see a particular reason to reject clearing the plugin manager cache there, although there's always the question of whether there's a previous reason it has to be there, it might be worth a git blame on the file to see if it switched places before.

So I did some digging:
* The latest commit that changed the \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions(); line was this commit: https://github.com/drupal/core/commit/c6fb130bd0b0d272cbf16e95579181f1dd... which is related to this still open issue: https://www.drupal.org/node/2380293
* This is the previous commit https://github.com/drupal/core/commit/4646c059ea07ca013a25648e2e6048ffb1... but it is also related to the same issue

Also added the TODO item to the patch.

mxr576’s picture

mxr576’s picture

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

Bumped version, although this should be backported to 8.7.x.

catch’s picture

+++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
@@ -457,11 +471,18 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       // Clear plugin manager caches.
+      // @todo Revisit why this can not run before the updateKernel() call,
+      // why that causing trouble with contrib modules

I think we can probably just have the first line of this comment (also missing a period). i.e. drop 'why that causing trouble with contrib modules'.

On #33 I did some extra investigation with

git log -S " \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions();"

This was added in #2155635: Allow plugin managers to opt in to cache clear during module install and hasn't moved around since, so I think we're probably OK to move it now.

mxr576’s picture

StatusFileSize
new14.31 KB
new698 bytes

Thanks for the review @catch, I fixed what you suggested.

mxr576’s picture

larowlan’s picture

Can you provide some more detail about the module you're having this issue with? Is it on drupal.org - I'd be interested in the service that's causing the issue. I've had similar problems in custom code and have been able to get around it with some defensive coding. My preference would be to do that instead of introducing the complexity this requires. We can't be sure there aren't side-effects to this, as there may be some modules that rely on things occurring the way they do now (whether or not that is correct), i.e just because it creates issues for some modules may not be the case for others.

  1. +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
    @@ -59,14 +67,17 @@ class ModuleInstaller implements ModuleInstallerInterface {
    -  public function __construct($root, ModuleHandlerInterface $module_handler, DrupalKernelInterface $kernel) {
    +  public function __construct($root, ModuleHandlerInterface $module_handler, DrupalKernelInterface $kernel, EventDispatcherInterface $event_dispatcher) {
         $this->root = $root;
         $this->moduleHandler = $module_handler;
         $this->kernel = $kernel;
    +    $this->initialEventDispatcher = $event_dispatcher;
    

    we need to provide a BC layer here - make the argument optional and if its not provided, use the \Drupal singleton to fetch it and trigger_error with a deprecation warning

  2. +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
    @@ -546,10 +566,10 @@ function ($definition) {
    -  protected function updateKernel($module_filenames) {
    +  protected function updateKernel(array $module_filenames) {
    

    this typehinting change is a BC break - yes its correct, but unfortunately we can't do it without risk of breaking sub-classes, so let's avoid doing it

  3. +++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
    @@ -561,6 +581,76 @@ protected function updateKernel($module_filenames) {
    +      $result[$item[0]->_serviceId] = $item;
    

    we shouldn't be relying on this anti-pattern, the _serviceId is not part of the API

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

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

macherif’s picture

I am still having the same issue. May be declared events should use plugin_manager instead of been stored on DB.

mxr576’s picture

Added [PP-1] Fix leaky and brittle container serialization solution as it describes and tries to resolve the issue with _serviceId.

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

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now 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: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

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

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.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.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.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.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now 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.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now 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.

borisson_’s picture

Status: Needs review » Needs work
Issue tags: +Bug Smash Initiative

The issue that was linked in #42 is now resolved, we can pick this up again.

The remarks in #39 needs to be picked up and we need to reroll the patch. I'm actually not sure if #2531564: Fix leaky and brittle container serialization solution actually fixed this as well.

andypost’s picture

The issue still makes sense as when modules uninstalled via UI the remaining request processing still working with container which have services/listeners initialized. And overtime complexity of contrib is growing so it will hit early or later

OTOH agree with #39 about complexity and overhead it brings

A compromise could be to add some defensive code to core, at least to give a hand to contrib to deal with it

Version: 10.1.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, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mstrelan’s picture

Component: system.module » extension system

I think this belongs in the extension system component, since ModuleInstaller is in the Drupal\Core\Extension namespace.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.