update module fails due to queue.expire & key_value records

Created on 28 April 2016, about 8 years ago
Updated 17 March 2024, 3 months ago

I had to manually delete rows from the queue table and key_value table in order to get the available updates page to work again. I cannot explain how I created the situation but I believe I did enough debugging that a core dev may be able to determine what caused the problem and if some additional action should be taken. If a core dev is interested, I can launch a new test server and restore a version of the database that demonstrates the problem, giving full ssh/mysql/Drupal access to a core dev.

The symptom is that Drupal was not showing any available release/update for core or for a few modules and there is nothing any user could do through the UI (flushing all caches, uninstall & re-install modules, run cron job and “check manually” for updates) to rectify the situation. This screenshot best shows the symptom:

Using XDebug, I followed the execution path of updateStatus() (in UpdateController.php) to update_get_available() (in update.module) to createFetchTask() to fetchData(). That in turn uses DatabaseQueue to claimItem() which executes this query to get the task:

SELECT data, created, item_id FROM queue q WHERE expire = 0 AND name = :name ORDER BY created, item_id ASC

When I first got to this point, I found three “update_fetch_tasks” rows (one each for Drupal core, imce, and views_slideshow as shown in the screenshot above). However, they all had an expire time which was 30 seconds later than the created time so claimItem() would never return one of these tasks to be processed (since the query above tests for expire=0).

My first question is, how and why does a row ever get inserted to DatabaseQueue with an expiration time given that claimItem() would NEVER return such a row?

I thought that if I deleted these tasks from the queue that they would be re-created but apparently I was wrong in that assumption. The problem remained even after deleting those three queue rows.

I then debugged the code that should be creating the tasks, but was not doing so even with the queue items/records deleted. I followed createFetchTask() in UpdateProcessor.php where I could see that $this->fetchTasks was getting fully populated on the first call because of the call to $this->fetchTaskStore->getAll(). That was apparently querying the key_value table “ WHERE collection = ‘update_fetch_task’.

So now it appears that the Drupal queue table and key_value tables were likely used together. When I deleted the key_value collection for “update_fetch_task”, suddenly the available updates started working again.

Is that truly the expected behavior? Should D8 better protect against the situation when a queue record is expired? Should D8 understand there is a problem when a key_value collection exists but the queue record/item does not exist? How did I manage to get in that situation in the first place? I feel there is a true bug here somewhere, but I have not been able to reproduce the cause of the problem. I hope this detailed description of the problem is helpful and as I said above, I have a DB backup which can demonstrate the problem if someone wants to see it. I take no offense if you say no and want to close the issue if you feel you have a good understanding for it. I'm just trying to save someone else a horrible support issue if someone else hits what I just did.

🐛 Bug report
Status

Needs work

Version

11.0 🔥

Component
Update 

Last updated about 14 hours ago

  • Maintained by
  • 🇺🇸United States @tedbow
  • 🇺🇸United States @dww
Created by

🇺🇸United States carteriii

Live updates comments and jobs are added and updated live.
  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇦🇺Australia ELC

    This is indeed the exact same issue as 2920285.

    I proposed a solution (patch) to fix core there which clears away all of the expired data before running either a manual check, or the main scheduled updates check. Patched into core it works quite well to keep the NARFs at bay: #2920285-50: Update module can get 'stuck' with 'no releases available' .

    Until this is all fixed, I also created a module which also clears out all of the dud state before running so I don't need another core patch: Update NARF!.

    The other option is to re-write the update manager to not use multiple state data sources to manage the update process. The contents of the keyvalue:update_fetch_task is never actually referenced, so this could be used for storing useful information like when it was created so that if the queue runner item for it disappears, it can easily be re-created to complete the job. At present it's only used as a semaphore which blocks the fetch task from being re-triggered.

    Updating referenced core to 11.x because this bug (same as 2920285) still exists there too.

  • 🇺🇸United States dianacastillo Miami

    thank you #38 works great !

  • 🇺🇸United States websiteworkspace

    A problem that appears similar the problem described throughout this thread occurred after updating a site to D10.2.4.

    After the 10.2.4 update, The "available updates" report displays only about 5 out of 60 or more installed contrib modules and themes.

    None of the suggestions provided in this thread have solve the problem.
    -
    1. When the "available updates" report broke, it continues to list a few modules, but not all.
    2. Modules installed after this problem began appear correctly in the "available updates" report.
    3. executing the following command via drush does not repair the problem:

    
    php -c ./php.ini vendor/bin/drush php:eval "\Drupal::keyValue('update_fetch_task')->deleteAll();"
    
    
    

    4. installing the https://www.drupal.org/project/update_narf module does not repair the problem.

    5. the following drush command displays all the contrib modules. Obviously drush is doing something different from the "available updates" report.

    php -c ./php.ini vendor/bin/drush pm-list --type=Module --no-core --format=list

    5. Does anyone have any additional suggestions or insights about this problem and about how to repair it?

    6. applying the patch below does not repair the problem. However, the patch does not appear to break anything.

    
    diff --git a/core/modules/update/src/UpdateProcessor.php b/core/modules/update/src/UpdateProcessor.php
    index a07a47c8f5..c4de5df0a3 100644
    --- a/core/modules/update/src/UpdateProcessor.php
    +++ b/core/modules/update/src/UpdateProcessor.php
    @@ -121,7 +121,7 @@ public function createFetchTask($project) {
         if (empty($this->fetchTasks)) {
           $this->fetchTasks = $this->fetchTaskStore->getAll();
         }
    -    if (empty($this->fetchTasks[$project['name']])) {
    +    if (empty($this->fetchTasks[$project['name']]) || $this->fetchTasks[$project['name']] !== $project) {
           $this->fetchQueue->createItem($project);
           $this->fetchTaskStore->set($project['name'], $project);
           $this->fetchTasks[$project['name']] = REQUEST_TIME;
    diff --git a/core/modules/update/tests/src/Functional/UpdateSemverCoreTest.php b/core/modules/update/tests/src/Functional/UpdateSemverCoreTest.php
    index 4573cff6c0..87fc2f03a9 100644
    --- a/core/modules/update/tests/src/Functional/UpdateSemverCoreTest.php
    +++ b/core/modules/update/tests/src/Functional/UpdateSemverCoreTest.php
    @@ -193,12 +193,12 @@ public function testFetchTasks() {
         $this->assertEquals(2, $queue->numberOfItems(), 'Queue contains two items');
         // Try to add a project again.
         update_create_fetch_task($project_a);
    -    $this->assertEquals(2, $queue->numberOfItems(), 'Queue still contains two items');
    +    $this->assertEquals(3, $queue->numberOfItems(), 'Queue still contains three items');
    
         // Clear storage and try again.
         update_storage_clear();
         update_create_fetch_task($project_a);
    -    $this->assertEquals(2, $queue->numberOfItems(), 'Queue contains two items');
    +    $this->assertEquals(4, $queue->numberOfItems(), 'Queue contains four items');
       }
    
       /**
    diff --git a/core/modules/update/update.install b/core/modules/update/update.install
    index b77654d622..b067b788dd 100644
    --- a/core/modules/update/update.install
    +++ b/core/modules/update/update.install
    @@ -87,6 +87,8 @@ function update_uninstall() {
    
       $queue = \Drupal::queue('update_fetch_tasks');
       $queue->deleteQueue();
    +
    +  \Drupal::keyValue('update_fetch_task')->deleteAll();
     }
    
     /*
    
    
    
Production build 0.69.0 2024