Problem/Motivation

Modules sometimes get installed without any entry in system.schema, because this is used to discover updates, this results in their updates never getting called either.

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Original report.

Debugging is using 8.1.1 while the patch is for 8.2.x. It would be nice to show how to reproduce this bug in 8.2.x but since it does not always occur I want to get it documented first. The PHP version is 5.6.20.

Some hook_update_N functions are getting called and some are not. For the "my_master" module the update hooks are getting called while for the "my_newsletter" the update hooks are not found. I do not know why some are found and others are not but we have had this occur twice for different people implementing update hooks for different modules.

In schema.inc the PHP function get_defined_functions() is called to get all the functions:

$functions = get_defined_functions();

Sorting and dumping the result for the my_newsletter module shows:

    [571] => my_master_form_alter
    [1086] => my_master_update_8001
    [1087] => my_master_update_8105
    [1088] => my_master_update_8111
    [572] => my_newsletter_help
    [573] => my_newsletter_mail

The update hook my_newsletter_update_8001 does not show up but the hooks for the my_master module are there. It appears that the my_newsletter.install file is not getting included. If you want to find the update hooks you had better include the .install file for my_newsletter! So add the line

module_load_include('install', $module);

Now the functions found are

    [571] => my_master_form_alter
    [1086] => my_master_update_8001
    [1087] => my_master_update_8105
    [1088] => my_master_update_8111
    [572] => my_newsletter_help
    [573] => my_newsletter_mail
    [1142] => my_newsletter_schema
    [1143] => my_newsletter_update_8101

Now I am getting prompted for database updates. There is no harm (except performance) in including this line to make sure the .install file is included.

CommentFileSizeAuthor
#74 2738879-74.hotfix.patch589 bytesdww
#68 2738879-2-68.patch4.67 KBalexpott
#68 66-68-interdiff.txt762 bytesalexpott
#66 2738879-66.patch4.7 KBmr.baileys
#65 2738879-65.patch4.69 KBmr.baileys
#65 interdiff.txt894 bytesmr.baileys
#61 2738879-61.patch4.58 KBmr.baileys
#61 2738879-61-test-only.patch3.24 KBmr.baileys
#58 interdiff-2738879-56-58.txt3.4 KBmr.baileys
#58 2738879-58.patch4.59 KBmr.baileys
#58 2738879-58-test-only.patch3.25 KBmr.baileys
#56 2738879-56.patch4.95 KBalexpott
#56 54-56-interdiff.txt2.34 KBalexpott
#54 interdiff-45-54.txt2.84 KBravi.shankar
#54 2738879-54.patch4.6 KBravi.shankar
#45 2738879-45.patch4.61 KBmr.baileys
#45 interdiff.txt574 bytesmr.baileys
#44 2738879-44.patch4.62 KBmr.baileys
#44 interdiff.txt1.45 KBmr.baileys
#42 2738879-42.patch3.96 KBmr.baileys
#37 2738879-test.patch3.28 KBdawehner
#37 2738879-test.patch3.28 KBdawehner
#34 2738879-34.patch909 bytesdawehner
#32 drupal-hook-update-not-called-2738879-32.patch6.27 KBtrobey
#30 drupal-hook-update-not-called-2738879-29.patch6.16 KBtrobey
#27 drupal-hook-update-not-called-2738879-26.patch6.16 KBtrobey
#21 drupal-hook-update-not-called-2738879-21.patch2.49 KBtrobey
#20 drupal-hook-update-not-called-2738879-20.patch2.58 KBtrobey
#19 drupal-hook-update-not-called-2738879-19.patch2.58 KBtrobey
#6 2.png119.38 KBJerenus
#6 1.png101.86 KBJerenus
#2 my_modules.tar_.gz5.13 KBtrobey
hook_update_N-is-not-called-1.patch504 bytestrobey
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

trobey created an issue. See original summary.

trobey’s picture

FileSize
5.13 KB

I have verified this with 8.2.0-dev. Attached are the two sample modules. I first enabled my_master and then uncommented the first update hook. Then I enabled my_newsletter with another update hook. Only the update hook for my_master shows up. I am using PHP 7.0.4 for this test.

cilefen’s picture

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Jerenus’s picture

Issue tags: +Triaged core major, +Baltimore2017
FileSize
101.86 KB
119.38 KB

@trobey

I think this might not be a bug, it looks like works as design.

I tried to reproduce the problem:
1. Put my_master and my_newsletter module to my module directory.
2. Install my_master without changes.
3. Install my_newsletter module and uncommented the my_master_update_8105() and my_master_update_8111() function.
4. Run update.php: 8105 and 8111 are showing up.
Master module update function
5. Add a my_newsletter_update_8113() function to my_newsletter.install file and run update.php.
8113

It seems works as design. The my_newsletter_update_8101() would only be script when the instance installed the old version of my_newsletter which without my_newsletter_subscribers table installed. It that right? If it is, should this be closed with works as designed?

Versions:
PHP 7.1.3
Drupal 8.4.x-dev

cilefen’s picture

Issue tags: -Triaged core major

I removed the "Triaged D8 major" tag because that is not the correct tag following a triage session.

cilefen’s picture

@Jerenus That's good work so far on triage. I could give you credit if you document the triage steps (even if brief). It is the only way to know if the triage has actually been completed. Here are some made-up examples of documented triage steps:

  • I tested the steps to reproduce and they did (or did not) work (so I am tagging it "Needs issue summary update").
  • I searched for duplicate issues but could not find any.
  • I checked the issue summary and it is accurate and up-to-date.
  • Etc...

Note that there are tags expected if it "Needs steps to reproduce".

Thank you!

cilefen’s picture

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

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

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Boobaa’s picture

Was fiddling with a similar problem: added a new mymodule_update_8004() which wasn't recognized by drush updb. Having a breakpoint in \Drush\Commands\core\UpdateDBCommands::getUpdatedbStatus() revealed this message:

mymodule module cannot be updated. It contains an update numbered as 8000 which is reserved for the earliest installation of a module in Drupal 8.x, before any updates. In order to update mymodule module, you will need to install a version of the module with valid updates.

Removing this offending mymodule_update_8000() resolved the problem for me.

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

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Fernly’s picture

This issue still exists.

When a module gets installed without install file, there is no system.schema record in the key_value table for this module.
If later on an install file is added containing an update hook, it's never triggered until a system.schema record in the key_value table is created for this module.

Reproduce:

  1. Install module without install file
  2. Add install file containing an update hook
  3. Clear cache
  4. Run drupal updates

You'll see that no update hooks get picked up.

robin.ingelbrecht’s picture

I can confirm #15. Same problem.
Any solutions?

catch’s picture

Priority: Major » Critical

Bumping to critical.

trobey’s picture

I spent some time digging into the code and have some thoughts.

  • The *.install files only have functions that are needed during the install and updates so this code should not be loaded except in those cases.
  • There should be a function added to the ModuleHandler class that loads the install files.
  • Any code elsewhere that loads the install files should be removed.
  • The new function in ModuleHandler class should be called by the update controller before running the updates.

There is a entry in the key value table and the update is still not found. It could still be an issue of what is in the key value table (not just schema of 8000). But with the items above this should no longer be an issue.

I can write a patch with the above items if there is no issues with the approach.

trobey’s picture

This is a first attempt at a patch. This loads the install files when running the database updates. It also provides the same functionality for any other places that need to load install files. I did not see where install files are getting loaded elsewhere in core so I did not address that part.

This can use testing to make sure it fixes the problem where update hooks are not found.

trobey’s picture

trobey’s picture

Another try to get tests to run.

trobey’s picture

Digging into the code further, the function drupal_load_updates() is used to load the install files. This calls drupal_get_installed_schema_version(). Usually this is the same as traversing all installed modules but there are some edge cases where the schema is missing. This seems to be causing the problem. It is safer to take the approach in the patch to check for install files for all modules. Once the code for the patch is added then drupal_load_updates() no longer needs to be called. I will try to update the patch when I have time. This should cover all the items in comment #18.

catch’s picture

Usually this is the same as traversing all installed modules but there are some edge cases where the schema is missing.

Ideally we should be finding out why that happens, as well as adding an update to correct the data for installed modules.

Cross-linking #2010380: Deprecate module_load_install() and replace it with ModuleHandler::loadInstall.

trobey’s picture

Ideally, yes. But reality is that the reason may be multiple and unforeseen. I have encountered a problem and been able to reproduce it and others have had the same experience. But I cannot take someone else's case and reliably reproduce it. So the function call to schema versions is unreliable and there is no way to ensure that it always is reliable. I will try to implement a more reliable method that updates the schema versions when it discovers a problem. But relying on the schema versions is just asking for more of these strange problems popping up.

catch’s picture

drupal_load_updates() hasn't been updated since Drupal 7 or 6.

I think the answer here might be to stop using the schema versions altogether there and use the module list instead.

trobey’s picture

That information is helpful and the link to the related issue helps. I think we are in agreement about how to proceed.

trobey’s picture

I updated the patch to include some of the suggestions.

pandaski’s picture

Thanks for the steps #15

Status: Needs review » Needs work

The last submitted patch, 27: drupal-hook-update-not-called-2738879-26.patch, failed testing. View results

trobey’s picture

Status: Needs work » Needs review
FileSize
6.16 KB

Status: Needs review » Needs work

The last submitted patch, 30: drupal-hook-update-not-called-2738879-29.patch, failed testing. View results

trobey’s picture

Status: Needs work » Needs review
FileSize
6.27 KB
dawehner’s picture

+++ b/core/includes/install.inc
@@ -76,17 +76,6 @@
-function drupal_load_updates() {

+++ b/core/modules/system/src/Controller/DbUpdateController.php
@@ -140,10 +140,10 @@ public static function create(ContainerInterface $container) {
-    require_once $this->root . '/core/includes/install.inc';
     require_once $this->root . '/core/includes/update.inc';
+    $modules = \Drupal::moduleHandler();
+    $modules->loadAllInstall();
 
-    drupal_load_updates();

I'm wondering whether we could provide a way smaller bugfix:

Fix this function, given in how many places it exists. My idea was to use loadAllIncludes('install') which has the right behaviour already.

Personally I don't think we need a separate .install loader.

alexpott’s picture

Issue tags: +Needs tests

+1 to a fix with a smaller surface area - especially less interface changes.

This looks testable.

Status: Needs review » Needs work

The last submitted patch, 34: 2738879-34.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

dawehner’s picture

I tried writing a test, to then realize that the current bugfix doesn't fix the problem. The patch attached solves the additional problem (assuming the schema version isn't set on install).

This issue still exists.

When a module gets installed without install file, there is no system.schema record in the key_value table for this module.
If later on an install file is added containing an update hook, it's never triggered until a system.schema record in the key_value table is created for this module.

Reproduce:

Install module without install file
Add install file containing an update hook
Clear cache
Run drupal updates
You'll see that no update hooks get picked up.

I've been thinking about this issue a bit more. I tried to actually reproduce this, but I'm confused.
I totally see the schema version being set. Looking at the code in /Users/dawehner/www/d8/core/lib/Drupal/Core/Extension/ModuleInstaller.php::install it really looks like 8000 should always be set.
This is certainly what happened locally when I renamed the install file.

One could argue that on some level having some more resilient code is fine.

alexpott’s picture

Status: Needs work » Needs review

The last submitted patch, 37: 2738879-test.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Status: Needs review » Needs work

The last submitted patch, 37: 2738879-test.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

catch’s picture

both of the patches in #37 are the test patches.

mr.baileys’s picture

Status: Needs work » Needs review
FileSize
3.96 KB

I tried reproducing this with the steps outlined in #15, but if I enable a module without an install file, the correct \Drupal::CORE_MINIMUM_SCHEMA_VERSION is stored in the KeyValue store as expected. If I subsequently add an install file and update hook, the update hook is correctly discovered and executed on the next updatedb run. As @dawehner points out in #34, it should not be possible to end up with a module that is enabled while the schema version is missing. Maybe this could happen if the module install fails after it is enabled, before the schema version is stored?

That said, I did encounter a live site where the schema version for a module without an update hook was missing, and newly created update hooks for that module were not discovered/executed.

Attached is a simple patch that ensures that for any enabled module, \Drupal::CORE_MINIMUM_SCHEMA_VERSION is used as installed schema version if version information is missing in system.schema. It includes the test from #37.

Status: Needs review » Needs work

The last submitted patch, 42: 2738879-42.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

mr.baileys’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
1.45 KB
4.62 KB

Fixed a bug, test now passes locally

mr.baileys’s picture

catch’s picture

Issue tags: +Drupal 8 upgrade path
catch’s picture

Issue tags: -Drupal 8 upgrade path

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.

junaidpv’s picture

#45 works for me.

george.karaivanov’s picture

#45 works for me as well.

alexpott’s picture

+++ b/core/modules/system/tests/fixtures/update/drupal-8.no-preexisting-schema.php
@@ -0,0 +1,21 @@
+// Enable action module.

This is installing the update_test_no_preexisting module

mr.baileys’s picture

Status: Needs review » Needs work
Issue tags: +Novice
alexpott’s picture

  1. +++ b/core/modules/system/tests/modules/update_test_no_preexisting/update_test_no_preexisting.info.yml
    @@ -0,0 +1,6 @@
    +core: 8.x
    

    Test modules don't need the core key

  2. +++ b/core/modules/system/tests/src/Functional/Update/NoPreExistingSchemaUpdateTest.php
    @@ -0,0 +1,40 @@
    +      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.6.0.bare.testing.php.gz',
    

    There are now 8.8.x dumps we should use. See #3089900: Drupal 8.8/8.9/9.0 update test coverage

ravi.shankar’s picture

Status: Needs work » Needs review
FileSize
4.6 KB
2.84 KB

I have re-rolled the patch #45 and made changes as suggested in #53.

Status: Needs review » Needs work

The last submitted patch, 54: 2738879-54.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

alexpott’s picture

Status: Needs work » Needs review
FileSize
2.34 KB
4.95 KB

Fixing the tests, ignoring coding standards where appropriate and making the test more robust.

catch’s picture

Title: hook_update_N is not called » system.schema can end up with missing schema information for some modules, resulting in hook_update_N() not getting called
Issue summary: View changes
+++ b/core/modules/system/tests/modules/update_test_no_preexisting/update_test_no_preexisting.install
--- /dev/null
+++ b/core/modules/system/tests/src/Functional/Update/NoPreExistingSchemaUpdateTest.php

This should probably be in UpdateSystem now.

+++ b/core/modules/system/tests/src/Functional/Update/NoPreExistingSchemaUpdateTest.php
@@ -0,0 +1,40 @@
+  /**
+   * {@inheritdoc}
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.8.0.bare.standard.php.gz',
+      __DIR__ . '/../../../../tests/fixtures/update/drupal-8.no-preexisting-schema.php',
+    ];
+  }

Should probably get the same treatment as in #3102059: Make tests of the update system use UpdatePathTestTrait instead of UpdatePathTestBase.

mr.baileys’s picture

Moved the NoPreExistingSchemaUpdateTest to the Drupal\Tests\system\Functional\Update\UpdateSystem namespace, switched to extending BrowserTestBase with the UpdatePathTestTrait instead of subclassing UpdatePathTestBase.

The last submitted patch, 58: 2738879-58-test-only.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

Status: Needs review » Needs work

The last submitted patch, 58: 2738879-58.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

mr.baileys’s picture

Status: Needs work » Needs review
FileSize
3.24 KB
4.58 KB

Messed up the namespace for the test in previous patch.

The last submitted patch, 61: 2738879-61-test-only.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

miro_dietiker’s picture

Issue tags: -#ContributionWeekend2020 +ContributionWeekend2020
longwave’s picture

+++ b/core/modules/system/tests/src/Functional/UpdateSystem/NoPreExistingSchemaUpdateTest.php
@@ -0,0 +1,54 @@
+    $connection->update('config')
+      ->fields([
+        'data' => serialize(array_merge_recursive($extensions, ['module' => ['update_test_no_preexisting' => 0]])),
+      ])

I think a comment explaining why we need to do this config change would be helpful.

mr.baileys’s picture

Made the comment more commenty.

mr.baileys’s picture

Same as above, but with the comment staying under 80 chars.

longwave’s picture

Status: Needs review » Reviewed & tested by the community

Thanks, this looks good now.

alexpott’s picture

Some v small tidy-ups. We shouldn't call $this->ensureUpdatesToRun(); as that ensures we have at least one update to run but what we really want to do here is to ensure that update_test_no_preexisting_update_8001() is run.

alexpott’s picture

Version: 8.9.x-dev » 8.8.x-dev
Status: Reviewed & tested by the community » Fixed

Crediting @catch for issue review, @Fernly for providing clear steps to reproduce the issue.

Committed and pushed 8faf10c9b1 to 9.0.x and b57a81c762 to 8.9.x. Thanks!

Committed 26189f0 and pushed to 8.8.x. Thanks!

My patches has been minor tidy-ups.

  • alexpott committed 8faf10c on 9.0.x
    Issue #2738879 by mr.baileys, trobey, dawehner, alexpott, ravi.shankar,...

  • alexpott committed b57a81c on 8.9.x
    Issue #2738879 by mr.baileys, trobey, dawehner, alexpott, ravi.shankar,...

  • alexpott committed 26189f0 on 8.8.x
    Issue #2738879 by mr.baileys, trobey, dawehner, alexpott, ravi.shankar,...
dww’s picture

Status: Fixed » Needs work

This seems to have broken tests on the 8.8.x branch:

05:41:48 PHP Fatal error:  Cannot declare class Drupal\Tests\system\Functional\UpdateSystem\NoPreExistingSchemaUpdateTest, because the name is already in use in /var/www/html/core/modules/system/tests/src/Functional/Update/NoPreExistingSchemaUpdateTest.php on line 15
05:41:49 
05:41:49 Fatal error: Cannot declare class Drupal\Tests\system\Functional\UpdateSystem\NoPreExistingSchemaUpdateTest, because the name is already in use in /var/www/html/core/modules/system/tests/src/Functional/Update/NoPreExistingSchemaUpdateTest.php on line 15
05:41:49 FATAL Drupal\Tests\system\Functional\Update\NoPreExistingSchemaUpdateTest: test runner returned a non-zero error code (255).
05:41:49 Drupal\Tests\system\Functional\Update\NoPreExistingSchemaUpd   0 passes   1 fails 

Not sure if we should hot-fix 8.8.x or revert this.

Thoughts?

Thanks!
-Derek

dww’s picture

Status: Needs work » Needs review
FileSize
589 bytes

A bit of local debugging... this test was added at

/core/modules/system/tests/src/Functional/Update/NoPreExistingSchemaUpdateTest.php

But the namespace says:

namespace Drupal\Tests\system\Functional\UpdateSystem;

phpunit is happy either way, but run-tests.sh is terribly confused.

This patch gets run-tests.sh passing locally again.

Not sure if it's better to move the file or change the namespace, but for now, the namespace was the smaller diff. ;)

Thoughts?

Thanks!
-Derek

longwave’s picture

Status: Needs review » Reviewed & tested by the community

The patch in #74 has the correct namespace, the UpdateSystem namespace was introduced in #3106395: Move tests that test the update system to UpdateSystem namespace and in 8.9.x and 9.0.x only, it wasn't backported.

dww’s picture

Oh yeah, I see what happened. There is no core/modules/system/tests/src/Functional/UpdateSystem in 8.8.x branch, so cherry-picking et al got confused. Test was moved to core/modules/system/tests/src/Functional/Update but the namespace wasn't changed to match. So I believe #74 is the right solution for 8.8.x to work properly again.

Reviews, corrections, improvements most welcome. ;)

Thanks,
-Derek

p.s. x-post. Cool, glad @longwave agrees!

  • larowlan committed 38f68cd on 8.8.x
    Issue #2738879 by mr.baileys, trobey, dawehner, alexpott, ravi.shankar,...
larowlan’s picture

Status: Reviewed & tested by the community » Fixed

Committed 38f68cd and pushed to 8.8.x. Thanks!

Status: Fixed » Closed (fixed)

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