Acquia connector "Subscription" service constructor may cause downstream chaos

Created on 19 April 2024, about 1 month ago
Updated 14 May 2024, 18 days ago

Problem/Motivation

Typically, service constructors do not invoke any in-depth logic. Even calls like $this->storage = $entityTypeManager->getStorage(...) are discouraged.

...however, Acquia Connector seems to invoke a ton of complex logic, which can ultimately end up invoking module hooks and other disruptive actions while the service container is building.

Let's find out how deep this rabbit hole goes...

Let's start our journey in the constructor of the \Drupal\acquia_connector\Subscription at https://git.drupalcode.org/project/acquia_connector/-/blob/4.x/src/Subsc....

This constructor calls ::populateSettings, which dispatches an event. So far, this shouldn't lead to any chaos...except when other Acquia modules come into play. Enter Acquia Search.

\Drupal\acquia_search\EventSubscriber\AcquiaSubscriptionData\AcquiaSearchData listens for this event and does some pretty wild things ( https://git.drupalcode.org/project/acquia_search/-/blob/3.1.x/src/EventS... )

One of the things that happens is the Drupal\Core\Extension\ModuleExtensionList service is invoked! This may be related to πŸ› ModuleHandler skips all hook implementations when invoked before the module files have been loaded Needs work , which can cause all sorts of nonsensical conditions.

The Drupal\Core\Extension\ModuleExtensionList invocation ultimately invokes other low-level hooks, including system_info_alter and leads to a discovery scan.

It's unclear exactly how this can manifest, but given the problems that we and others have had only with Acquia hosted sites, it's definitely worth exploring. I've also included πŸ› Shield middleware invokes hooks before modules are loaded, corrupting module_implements cache Needs work as a related issue, see comment #10 for a possible symptom of invoking low level hooks in unexpected / unsupported contexts.

Steps to reproduce

Proposed resolution

Do not call ::populateSettings() from the constructor. Instead,

  1. Call ::populateSettings() from ::getSettings() and ::getProvider().
  2. Exit early from ::populateSettings() if it has already been called.
  3. Replace all uses of $this->settings and $this->settingsProvider with calls to the getters.

Remaining tasks

User interface changes

API changes

Data model changes

Issue Credits

Be sure to credit Kevin Quillen if this issue ends up generating credits; this was a collaborative effort over the course of more time than either of us would probably care to admit.

πŸ› Bug report
Status

Fixed

Version

4.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States Luke.Leber Pennsylvania

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @Luke.Leber
  • πŸ‡ΊπŸ‡ΈUnited States Luke.Leber Pennsylvania
  • πŸ‡ΊπŸ‡ΈUnited States Luke.Leber Pennsylvania
  • Pipeline finished with Success
    about 1 month ago
    Total: 505s
    #151255
  • Status changed to Needs review about 1 month ago
  • πŸ‡ΊπŸ‡ΈUnited States Luke.Leber Pennsylvania

    Let's see what the test bot thinks.

  • Pipeline finished with Failed
    about 1 month ago
    Total: 467s
    #151264
  • πŸ‡ΊπŸ‡ΈUnited States Luke.Leber Pennsylvania
  • Status changed to Needs work about 1 month ago
  • πŸ‡ΊπŸ‡ΈUnited States Luke.Leber Pennsylvania

    NW for test fails.

  • πŸ‡ΊπŸ‡ΈUnited States kevinquillen

    Can confirm, a handful of us have been chasing this around for months. AC is a common module between us.

  • πŸ‡ΊπŸ‡ΈUnited States benjifisher Boston area

    I am adding more detail to the proposed resolution and replacing links to issues with tokens.

  • πŸ‡ΊπŸ‡ΈUnited States benjifisher Boston area

    The first test failure I looked at is in ConfigureApplicationFormTest. It looks as though ConfigureApplicationForm::submitForm() calls Subscription::getSubscription(), which calls Subscription::hasCredentials(), and that function uses $this->settings directly instead of getSettings().

    I think all references to $this->settings should be replaced with $this->getSettings(). (No, not the reference inside populateSettings().) That might fix a lot of the test failures.

  • First commit to issue fork.
  • Status changed to Needs review about 1 month ago
  • πŸ‡ΊπŸ‡ΈUnited States japerry KVUO

    Took a crack at this. For the most part, I agree with the changes.

    I think all references to $this->settings should be replaced with $this->getSettings(). (No, not the reference inside populateSettings().) That might fix a lot of the test failures.

    +1 -- one of the issues with populateSettings is that its supposed to repopulate (execute the event again) settings whenever its called. Adding the check in this method means that the first time its invoked, you could end up with the wrong settings. This is the case with tests because they call populateSettings directly after some values are changed, and the settings object gets first set when installing the module, with unfortunately null values within the object, causing it to be a valid object just with null values within it.

    I've made some tweaks, we'll see if the tests are passing now.

  • Pipeline finished with Failed
    about 1 month ago
    Total: 2032s
    #157709
  • Pipeline finished with Failed
    about 1 month ago
    Total: 7033s
    #157739
  • πŸ‡ΊπŸ‡ΈUnited States Luke.Leber Pennsylvania

    !48 looks good to me. I understand this is basically impossible to test, but there shouldn't be any harm in delaying the collection of settings.

    We've sporadically experienced weird "should never happen" things on the platform, so after this lands, I'll keep this issue in mind and chime in if another inexplicable thing (i.e. cache corruption) happens afterwards. I think that's the only reasonable evaluation we can do against the theory written out in the I.S.

  • Pipeline finished with Success
    about 1 month ago
    Total: 3171s
    #159914
  • Pipeline finished with Skipped
    about 1 month ago
    #159999
  • Status changed to Fixed about 1 month ago
  • πŸ‡ΊπŸ‡ΈUnited States japerry KVUO

    Committed! Thanks everyone for your reports and testing of it.

  • πŸ‡ΊπŸ‡ΈUnited States kevinquillen

    Many thanks

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

Production build 0.69.0 2024