RecipeRunner::processInstall() installs modules one by one

Created on 7 January 2025, 5 months ago

Problem/Motivation

Testing installing a module via project browser, I noticed 10 separate calls to ModuleInstaller::install(). The project browser request to install the recipe required a total of over 160mb of memory and took 14 seconds.

This is from RecipeRunner::processInstall() which installs modules one by one.

It means it can't take advantage of πŸ“Œ Add the ability to install multiple modules and only do a single container rebuild to ModuleInstaller Active , at all, which by itself will be a significant improvement from 11.2 onwards, but ModuleInstaller::install() in 11.1 already has some optimisations when multiple modules are installed at once.

Steps to reproduce

Proposed resolution

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

πŸ“Œ Task
Status

Active

Version

11.0 πŸ”₯

Component

recipe system

Created by

πŸ‡¬πŸ‡§United Kingdom catch

Live updates comments and jobs are added and updated live.
  • Performance

    It affects performance. It is often combined with the Needs profiling tag.

Sign in to follow issues

Comments & Activities

  • Issue created by @catch
  • πŸ‡¬πŸ‡§United Kingdom catch
  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    Note we need to think about \Drupal\Core\Recipe\RecipeRunner::toBatchOperationsInstall() too

    It's likely this change will result in quite a bit of refactoring.

  • πŸ‡¬πŸ‡§United Kingdom alexpott πŸ‡ͺπŸ‡ΊπŸŒ

    The tricky bit here will be

        // Disable configuration entity install but use the config directory from
        // the module.
        \Drupal::service('config.installer')->setSyncing(TRUE);
        $default_install_path = \Drupal::service('extension.list.module')->get($module)->getPath() . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY;
        // Allow the recipe to override simple configuration from the module.
        $storage = new RecipeOverrideConfigStorage(
          $recipeConfigStorage,
          new FileStorage($default_install_path, StorageInterface::DEFAULT_COLLECTION)
        );
    

    @phenaproxima suggested wrapping all the config from all the modules together. This might work because modules cannot have conflicting config - we have the PreExistingConfiguration exception that handles that. I'm concerned that it might not work because that when you install the first module it'd discover all the configuration from the modules that are yet to be installed. Not sure how that's going to work out.

  • πŸ‡¨πŸ‡¦Canada mandclu

    +1 on the need for this. I can install the Event Platform project (which has loads of nested dependencies) in less than 20 seconds via the Drupal UI or drush. If I implement a recipe that installs this project (and does nothing else, even forcing the configuration to load) then the recipe runner tries for several minutes and then inevitably fails.

  • πŸ‡¨πŸ‡¦Canada mandclu

    I will also add that this seems to severely impact the intended reusability of the recipes within Drupal CMS. I can include one such recipe in my own recipe (tested successfully with drupal_cms_admin_ui) but my recipe fails to apply if I add another (tested by adding drupal_cms_anti_spam, which only adds another 5 dependencies, based on the command line output).

Production build 0.71.5 2024