Update numbers are set to max even when update fails

KarenS - January 10, 2008 - 22:26
Project:Drupal
Version:6.x-dev
Component:update system
Category:bug report
Priority:normal
Assigned:Unassigned
Status:closed
Description

Maybe I missed something and this was intended, but it used to be if you didn't want an update to run you could return array('success' => FALSE) to keep it from running, and the schema version number would not be updated so it still shows up as an update that needs to be run.

Now if I try to force an update not to run, it doesn't run, but it does reset the schema version so it looks like it ran, and the next time I go in there it shows no updates are needed, which means it will *never* run.

The reason I need this is because of the new behavior that runs updates even for disabled modules. This is new behavior and I need to prevent some of those updates from running if the modules are disabled. The biggest problem is in CCK where the field modules' updates run before the content module, and they run even if the content module is disabled, which introduces all kinds of quirkiness.

If this is intended behavior to not allow me to postpone the update until I'm ready for it, I'd like to verify that.

#1

pwolanin - January 10, 2008 - 22:42

I didn't write that patch, but sounds like a bug that a return of FALSE doesn't have an effect

#2

pwolanin - January 11, 2008 - 02:24
Status:active» needs review

I don't see anywhere that this patch would have made that change: http://drupal.org/node/194310 Also, I see no evidence from D5 update.php that such a flag was respected. Are you sure about this?

I'm not quite sure about the solution you're suggesting. What if a module has multiple updates - should all be aborted if one fails?

Attached patch adds an explicit flag to tell update.php that the function can't run. Tested using the second patch which adds a dummy update function (please don't commit it!). If later functions for the same module succeed, then I guess you have the same problem as before.

AttachmentSize
abort-update-208602-2.patch 1.08 KB
test-abort.patch 661 bytes

#3

KarenS - January 11, 2008 - 02:51

That patch did not do anything, I suspect the problem is older than that, but can't quite figure it out.

Ignore my reasons for wanting this, that just muddies the issue. Take this example instead:

A module is currently set to schema version 5999. Update_6000 returns array('success' => false), which could be the result of a failed sql query or anything else where the update returns a failure message. Update.php then happily sets the schema version to 6000, as though the update was successful. The next time you go to update.php it will say there are no more updates, but update 6000 never happened. If there is also an update_6001, then what will happen? It will go ahead and do that update, too.

So the question is, is that what ought to happen? It doesn't seem intuitive. If we have gone to all this trouble of creating a way to report a failure, why do we treat it as though it was a success? Shouldn't we be using a report of a failure as a message to stop the update? And shouldn't we have a way to abort an update if an important component that affects later updates has failed?

And the reason why this will more of an issue than before is because these updates used to only run on modules that were installed, so you could control them, a little bit, by not enabling the module until you are ready to update it, but now I get all updates running automatically for every single module on my server, whether or not they are installed, and whether or not the modules they depend on are installed, so there are more ways they might go wrong.

Maybe this is all by design and I missed the discussion, I'm just raising the issue because it seems odd to me. And that's why instead of saying 'This is a bug!' I said 'Is this intended behavior?'.

#4

pwolanin - January 11, 2008 - 04:28

I think this is in part by design.

Errors in a single query are not too uncommon in updating a real DB, so I think it would be incorrect to abort the process if a single query fails.

The patch above is intended to give you a way to prevent updates from running (as you desired) for example, add this sort of code to each update function:

<?php
function mymodule_update_6000() {
 
$ret = array()

  if (!
module_exists('mymodule')) {
   
$ret['cannot update'] = array('success' => FALSE, 'query' => "Mymodule must be enabled for it to update.");
    return
$ret;
  }
  ...

  return
$ret;
}
?>

#5

chx - January 11, 2008 - 08:41
Status:needs review» reviewed & tested by the community

Though this borders a feature request I can see that the new update behaviour might cause problems so this is quite OK. The change is almost 100% backwards compatible, I can't imagine someone already setting this in their updates. The added code is minimal and it's not even loaded on every page, so I say let's go with this.

#6

chx - January 11, 2008 - 08:45

On second thought, we use $ret['#finished'] so I added a few hashmarks to pwolanin's patch.

AttachmentSize
abort-update-208602-6.patch 1.08 KB

#7

KarenS - January 11, 2008 - 10:57

This looks like a good solution, except I would reword the flag from '#cannot update' to '#abort', which is only one word and is really clear.

If an update is aborted, the system is going to go on and try the next one, and if it works, update the schema version, undoing this effort, but there is a work-around for that. Since the schema version doesn't get reset on the aborted update, I can test in later updates for the schema version and abort those updates, too, until the underlying one is successfully completed. That's a little messy, but should work, and it wouldn't work without this patch.

So I think this solution would help out quite a bit, if gabor is agreeable to adding it.

I'm going to go back and test this, just to be sure.

#8

KarenS - January 11, 2008 - 12:42

OK, works like a charm. The updates I use this new flag on do not get their schemas updated and do not run, and display on the next visit to update.php as updates that have not yet been done, everything I was trying to accomplish.

#9

KarenS - January 11, 2008 - 12:44

And here's my slightly altered patch, changing to the use of '#abort' and adding a big more documentation to the code.

AttachmentSize
update.php_.patch 1.33 KB

#10

pwolanin - January 11, 2008 - 14:42
Status:reviewed & tested by the community» needs work

@KarenS - I considered the word "abort", but I thought something like "cannot update" is much clearer and more self-documenting. A developer returning "abort" might reasonably expect that the ENTIRE update process would cease at that point, rather than it being a flag that that single update did not run.

#11

catch - January 11, 2008 - 15:31
Status:needs work» needs review

#6 is still valid though it seems.

#12

pwolanin - January 11, 2008 - 16:02
Status:needs review» reviewed & tested by the community

yes #6 is fine with me.

#13

webchick - January 11, 2008 - 16:03
Status:reviewed & tested by the community» needs review

Then let's do #update_failed or #update_error or something. I also think #abort is fine. "#cannot_update" is too ambiguous, imo, and it's weird to begin a two-word property name with a verb.

#14

pwolanin - January 11, 2008 - 16:19

"#update_failed" sounds fine.

AttachmentSize
abort-update-208602-14.patch 1.08 KB

#15

KarenS - January 11, 2008 - 16:20

A one-word term would be better than two, because of problems figuring out if there is supposed to be a space or an underscore between them. The patch uses a space ('#cannot update'), which is inconsistent with other FAPI-like properties, I would use an underscore.

I agree with webchick that reversing the words makes more sense, I thought that '#cannot update' sounded odd but wasn't sure why, but she's right that it's the word order that's odd.

I still think #abort is clear enough, but can see the issue, '#update_error' is OK, or how about '#skipped' or '#failed' or '#omitted', or just '#error'?

Plus I added some extra documentation in #9 that might still be useful so developers understand that skipping one update will not stop the others from running:

<?php
// Note that this will not prevent later updates from running and updating
// the schema version, so if you have critical updates that must keep
// later updates from happening, you will need to add code to check the
// schema version in later updates and abort them, too.
?>

#16

KarenS - January 11, 2008 - 16:21

Oops, cross-posted with pwolanin. My points in #15 still stand, but #14 is OK with me.

#17

pwolanin - January 12, 2008 - 03:21

here's a re-roll with expanded comments along the lines suggested by KarenS

AttachmentSize
abort-update-208602-17.patch 1.31 KB

#18

chx - January 12, 2008 - 14:52
Status:needs review» reviewed & tested by the community

Let's try RTBC now. webchick suggested, pwolanin coded, KarenS agreed and I am fine with whatever so all participants agree on the latest #14 patch.

#19

moshe weitzman - January 12, 2008 - 19:26

since you guys are working on update.php, perhaps you can answer my UI question at http://drupal.org/node/105302.

#20

Gábor Hojtsy - January 15, 2008 - 10:51
Status:reviewed & tested by the community» needs review

+ // Note that this will not prevent later updates for the same module from running
+ // and updating the schema version. Thus, you will need to add code to check the
+ // schema version in later updates and abort them, too.

Why? To me this sounds like: we have an incomplete abort feature here, which you will need to complement with custom code all on your own. Why not abort the whole update process for this function if an update "completely" fails? As Karen explained above, it means that further updates will fail or lead to an inconsistent state, so developers would need to implement this version check in all their subsequent update functions "for life" once they use this failure possibility in any of them.

#21

KarenS - January 15, 2008 - 12:05

Are you agreeable to adding that in at this point? I agree it would be a better solution, but assumed that was too much of a change for late in the cycle.

I agree that there may be reasons not to abort on every failure, some failures are not fatal, but we certainly should have a way to force an abort.

#22

pwolanin - January 15, 2008 - 12:19

@Gabor - I was going for a workable (if not ideal) solution that touched as little code as possible. Perhaps there should be a way (even this flag) to abort all updates for a particular module, though I don't think it makes sense to allow one module abort ALL site updates.

#23

Gábor Hojtsy - January 15, 2008 - 12:26

pwolanin: I am talking aborting all updates for the current module, not all site updates. As it is now, module updates are treated as being on their own, without cross-dependencies on each other (this is part of why we have a mostly linear system.install only flow of update functions). So aborting a module update should not abort other module updates.

#24

pwolanin - January 15, 2008 - 12:51

@Gabor - I'll have to dig more deeply, but from my brief look it seemed as though ALL of the update functions were queued independently with the batch API. Doing what you suggest will require more serious hacking.

#25

pwolanin - January 15, 2008 - 12:51

@Gabor - I'll have to dig more deeply, but from my brief look it seemed as though ALL of the update functions were queued independently with the batch API. Doing what you suggest will require more serious hacking.

#26

Gábor Hojtsy - January 15, 2008 - 13:06

Well, if you do find that it requires serious hacking, then it would be good to document the findings here, so we can have that info in the future, and see what we can do for now.

#27

KarenS - January 15, 2008 - 13:28

I think I found a way to do it. Patch attached. I tested this by trying to abort a content module update and it seems to work fine.

AttachmentSize
update.php_.patch 3.26 KB

#28

KarenS - January 15, 2008 - 14:03

I tested that this works to stop both the current and later updates for an individual module with multiple updates, and that it doesn't prevent other modules from updating, and it works fine. I did find one place where I needed to fix an undefined index for updates that are not aborted, so a revised patch is attached.

AttachmentSize
update.php_.patch 3.27 KB

#29

Gábor Hojtsy - January 16, 2008 - 13:01

IMHO this is the desired behavior and the patch does not look like changing much :) So let's get this reviewed and tested a bit more.

#30

pwolanin - January 16, 2008 - 13:19

ok - doesn't look bad in terms of LOC changed.

#31

webernet - January 16, 2008 - 18:56
Status:needs review» needs work

Did some basic testing with the patch and $ret['#abort'] = array('success' => FALSE, 'query' => 'Canceled!!!'); at various spots.

Ran update with patch applied and no 'abort' --> OK

Ran update with patch applied and 'abort' in system_update_6005() --> Fatal error in book.install ???

Ran update with patch applied and 'abort' in system_update_6042() --> Finishes, runs updates of other modules. Re-run update.php, it offers: system 6043+ (OK), already run updates of other modules (comment, book, blogapi)...

Also, when it aborts - there is no message at the top of the results page.

#32

KarenS - January 16, 2008 - 20:33

I think the fatal error in the book install is because it aborts in a batch before the batch has returned finished=1. Any batch update that returns finished < 1 will give you a fatal error in the current update code. I'm not sure if this patch should change that behavior, or how.

I see no reason for a message at the top of the results page, the message will show up in the list at the bottom showing the update failed with whatever text you put in 'query'. To me that seems like the logical way to do it.

#33

KarenS - January 16, 2008 - 20:51

And there's another problem with testing abort in the system install, which is that if the system install fails, the whole update should abort, not just the system update, so this is a different case than an individual module update. The abort patch above is designed to only abort a specific module, not the whole system. Aborting a system install is going to take something different.

I misread your post in my comment above, I thought you were testing the book.install when you had a failure, not a system install. The fatal error there would be that an important system component did not get finished which would obviously break dependent module updates later.

So the question is whether or not this should be intended to work for the system update. I would say not, because the system update is so integral to everything else.

If it should, that patch will need to be adjusted to check if it is a system update that has failed, and behave completely differently. If it is not, we should test other installs than the system install.

#34

KarenS - January 16, 2008 - 20:52

Change 'install' to 'update' in my comments above. I was typing too quickly.

#35

catch - January 16, 2008 - 21:39
Status:needs work» needs review

This all sounds sane to me, makes no sense for this patch to try to deal with system_update failures. Back to CNR.

#36

Gábor Hojtsy - January 17, 2008 - 20:06
Status:needs review» fixed

Since we are not about to deal with cross-dependency in update functions, and the latest code looked code and proved good in the tests, I went ahead and committed it. Thanks!

#37

pwolanin - January 20, 2008 - 01:09

This needs to be documented now on the handbook and also the 5.x -> 6.x update page

#38

webernet - January 20, 2008 - 16:17
Status:fixed» needs work

This broke updates.

Update a 5.x site to 6.x -- check status report, and it reports that the DB is out of date because none of the updates that were performed were recorded in the DB.

#39

webchick - January 20, 2008 - 18:03
Title:Update numbers are set to max even when update fails» RC3-breaker: Update numbers are set to max even when update fails

Well that's certainly not good...

#40

Gábor Hojtsy - January 21, 2008 - 11:50
Status:needs work» needs review

Well, looks like the schema version update was wrapped in a bad conditional. We should update it is the #abort flag *is* empty, but before the attached patch it is only updated when the #abort flag is not empty. So the conditional should be flipped IMHO. Please test.

AttachmentSize
bad-conditional.patch 747 bytes

#41

webernet - January 21, 2008 - 14:05
Status:needs review» reviewed & tested by the community

Tested OK.

Revised patch to clarify the code comment.

AttachmentSize
bad-conditional.patch 931 bytes

#42

Gábor Hojtsy - January 21, 2008 - 15:06
Status:reviewed & tested by the community» fixed

Thanks, committed.

#43

Anonymous (not verified) - February 4, 2008 - 16:06
Status:fixed» closed

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

#44

fgm - March 30, 2008 - 08:54
Priority:critical» normal
Status:closed» needs work

The documentation about hook_update_N does not reflect these changes, although update.php relies on the hook implementations to support this new behaviour.

This is no longer critical, so I'm changing status, but it should be fixed nonetheless.

#45

catch - March 30, 2008 - 13:37
Title:RC3-breaker: Update numbers are set to max even when update fails» Update documentation for #abort flag in update.php

#46

drewish - April 23, 2008 - 09:45
Status:needs work» fixed

i just copied and pasted karrens's comments into the hook_update_N docs.

#47

catch - April 23, 2008 - 10:28
Title:Update documentation for #abort flag in update.php» Update numbers are set to max even when update fails

Back to original title.

#48

Anonymous (not verified) - May 7, 2008 - 10:31
Status:fixed» closed

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

 
 

Drupal is a registered trademark of Dries Buytaert.