Problem/Motivation
The site I'm working on has a large number of nodes (~15,500). We fairly consistently run into an issue where views_bulk_operations doesn't process all of the selected items when I "Select all on this page", nor when I "Select all results in the view" I've included some steps to reproduce with the "Select all results in the view"
When I did some debugging for the "Select all on this page", I find that view_bulk_operations seems to successfully POST all 50 checkbox values to the backend (i.e.: /views-bulk-operations/ajax/content/page_1, and the confirmation step seems to show 50 nodes; but when the actions actually run, they don't act on all the items. The number of items processed also seems to vary... sometimes its 42, sometimes it's 46, sometimes it's 48, sometimes its all 50. When I select all items in the view, it's often low, like 2 items processed, or 0 items processed.
Doing a bit more debugging of the data stored in the private tempstore, I see...
{
"owner": "25",
"data": [
"view_id" => "content",
"display_id" => "page_1",
"list" => [
// Sometimes this is empty and, when exclude_mode = false, nothing gets processed.
// Sometimes there are less than 50 nodes here, and less than 50 nodes get processed.
// Sometimes there are 50 nodes here, and all 50 nodes get processed.
],
"exclude_mode" => false,
"batch" => true,
"batch_size" => 10,
"total_results" => "15472",
"relationship_id" => "none",
"arguments" => [],
"exposed_input" => [
// (redacted)
],
"bulk_form_keys" => [
// This seems to always have the correct number of entries, i.e.: if I select all on a page, I see 50 values here, even if there are less than 50 values in object.data['list'] above.
],
"redirect_url" => Drupal\Core\Url {#5336},
],
"updated": 1637280422,
}
My guess is that whatever is supposed to copy/move data from object.data['bulk_form_keys'] to object.data['list'] doesn't always move everything.
It's also hard to reproduce this on sites without many nodes, fields, or content types. Maybe it runs out of time or memory? But I'd expect to see an error or message in the log if that happened.
Steps to reproduce
git clone --branch '9.3.x' https://git.drupalcode.org/project/drupal.git- The latest commit when I ran this test case was
72d15850a271e3718bf74d71a8207614c79b6918, committed Tue Dec 7 16:55:28 2021 +0100 (authored Thu Nov 25 15:52:00 2021 +0100 - it was a cherry-pick).
- The latest commit when I ran this test case was
composer installcomposer require 'drush/drush' 'drupal/devel:^4.1'cd modules/git clone --branch '4.0.x' https://git.drupalcode.org/project/views_bulk_operations.git- The latest commit when I ran this test case was
d83b999e87dac745057a1a746a0ba038d63258fdcommitted Mon Nov 15 10:26:13 2021 +0100.
- The latest commit when I ran this test case was
cd ..drush -y si minimal- Log in as the super-administrator
- Go to
/admin/modules. Install the modules with machine namesviews_bulk_operations,views_ui,devel_generateand all their dependencies. - Go to
/admin/structure/views/view/content:- Add field "Global: Views bulk operations". Select Action "Unpublish content item" and check "Add confirmation step". Select Action "Publish content item" and check "Add confirmation step". Apply.
- Remove field "Content: Node operations bulk form". Apply.
- Save the view.
- Go to
/admin/structure/types/add. Set name =Page. Leave all other settings at default. ClickSave content type - Go to
/admin/config/development/generate/content. Set: Content type = (checked) (this will check "Page" automatically), and How many nodes would you like to generate? =12000. Leave all other settings at their default values. ClickGenerate - Go to
/admin/content. You see a table of 50 nodes, ordered by "Updated", descending. - Select all items on the page using the checkbox. Select Action "Unpublish content item".
- Expected behavior: The
#edit-multipagedetails element says "Selected 50 items in this view". Expanding the details element shows a list of all 50 items selected. - Actual behavior: The
#edit-multipagedetails element says "Selected 50 items in this view". Expanding the details element shows "No items".
- Expected behavior: The
- Click
Apply to selected items. - You see a page saying "Are you sure you wish to perform "Unpublish content item" action on 50 entities", and a list of 50 "Items selected". Click
Execute action. - A batch process runs.
- You are returned to
/admin/content. You see the status message "Action processing results: Unpublish content item (50).". You see a table of 50 nodes, ordered by "Updated", descending. The first 50 rows in the table are unpublished. - Check "Select / deselect all results in this view (all pages, 12000 total)" Select Action "Unpublish content item". Click
Apply to selected items. - You see a page saying "Are you sure you wish to perform "Publish content item" action on 12000 entities? / Action will be executed on all items in the view." Click
Execute action. - A batch process runs.
- You are returned to
/admin/content. You see the status message "Action processing results: Publish content item (12000)." - You see a table of 50 nodes, ordered by "Updated", descending.
- Expected behavior: The first 50 rows in the table are published.
- Actual behavior: The first 28 rows in the table are published. The remaining 22 rows are unpublished. (or at least, that's what happened in my run)
Note that there are no notice, warning, or error messages:
$ drush -y wd-list
---- -------------- ---------------- ---------- -----------------------------------------
ID Date Type Severity Message
---- -------------- ---------------- ---------- -----------------------------------------
21 08/Dec 09:13 node Notice Added content type Page.
20 08/Dec 09:12 system Info devel_generate module installed.
19 08/Dec 09:03 page not found Warning /admin/stucture
18 08/Dec 09:02 system Info views_ui module installed.
17 08/Dec 09:02 page not found Warning /admin/structure/views
16 08/Dec 09:02 page not found Warning /admin/structure/veiws
15 08/Dec 09:02 system Info views_bulk_operations module installed.
14 08/Dec 09:02 system Info views module installed.
13 08/Dec 09:01 user Notice Session opened for admin.
12 08/Dec 09:01 cron Info Cron run completed.
---- -------------- ---------------- ---------- -----------------------------------------
Proposed resolution
(To be determined)
Remaining tasks
(To be determined)
User interface changes
(To be determined)
API changes
(To be determined)
Data model changes
(To be determined)
| Comment | File | Size | Author |
|---|
Issue fork views_bulk_operations-3253404
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
mparker17(fixed some formatting issues in the issue summary)
Comment #3
liquidcms commentedComment #4
graber commentedInteresting.. selection uses AJAX to save data.. maybe those callbacks take too long with large numbers of entities or are not executed at all due to some browser error?
Did you check the browser console?
Comment #5
graber commentedAlso.. it may be an issue with your hosting not processing some of those requests. Just tried to reproduce taking the described steps and no luck - all works fine and AJAX requests are super fast with over 12000 nodes (using Docker locally).
Please include more details if possible, maybe then someone will be able to help.
Comment #6
liquidcms commentedBTW.. my issue, with D9.2 and VBO 4.0.0. is on a page with < 40 nodes.
Comment #7
mparker17@Graber, thanks for the response. I'll try to answer your questions as best I can. I spent some time digging into the problem earlier this month, and while I can't point to a specific problem yet, I'll try to communicate what I know.
To answer the easiest questions first:
The issue was originally discovered on a server dedicated to this website (i.e.: not shared hosting) with 2x 3.1 GHz Intel Xenon Platinum 8175M CPUs and 8 GB of RAM.
All servers running nginx, PHP 7.3 FPM and PostgreSQL 10.17.
The drupalvm box has a
memory_limitof -1 (i.e.: unlimited); the Xenon server has amemory_limitof 512M.The drupalvm box had a
max_execution_timeof 0 (i.e.: unlimited); the Xenon server has amax_execution_timeof 60 seconds.memory_limitormax_execution_time. Note thaterror_reportingwas set toE_ALL4d7c1ebc4e(from 2021-12-08); a clone of views_bulk_operations on branch 4.0.x at commita6b668b(from 2022-01-03); and a copy of drupal/devel at version 4.0.0 (note this is not the latest version, due to a typo in my composer.json that I just noticed while typing thisSince there are so many nodes, and problems only seem to start showing up in batch operations after ~6000 nodes have been processed, step-through debugging is fairly impractical, so what I was doing was inserting
\Drupal::logger('channel')->debug('Message', ['@variable' => $foo]);statements into VBO, and then using SQL to analyze the results.I've noticed some notably-unusual behaviours:
ViewsBulkOperationsActionProcessor::initialize()tries to enqueue all 12,000 nodes exactly once (i.e.: expected behaviour).During the second phase of the bulk operation,
ViewsBulkOperationsActionProcessor::populateQueue()queues up 10 nodes to be processed, andViewsBulkOperationsActionProcessor::process()processes the 10 queued nodes. This enqueue-10-process-10 is repeated 1200 times (i.e.: expected behaviour), but...Reading the code in ViewsBulkOperationsActionProcessor, it doesn't seem like ::populateQueue() nor ::process() have any obvious logic errors.
Something I noted, though, is that they both call the
\Drupal\views_bulk_operations\Service\ViewsBulkOperationsViewDataservice to get data about the rows. This service also gets called when the VBO field is being displayed, and given the manner thatViewsBulkOperationsActionProcessoruses theViewsBulkOperationsViewDataservice, it is at least a possibility thatViewsBulkOperationsViewDatacould be returning duplicate results. Reading that service, I don't see any obvious logic errors, and I'm not certain that it is the thing returning duplicate rows, or if it something deeper (i.e.: Views).Comment #8
graber commentedCan you try to add an ID sort to the view (as the last sort)? You shouldn't have same results on subsequent pages but I'll be surprised if your issue will go away since that's what ViewsBulkOperationsActionProcessor does when creating a list..
Comment #9
mparker17I tried this on a freshly-created site, with newly-generated content, and a bunch of the 50 items from the front page reappeared as early as page 2 of the results. I added a column of NIDs to make it easier to see the duplicates. Please find screenshots attached, including one of the View itself and the queries run during the preview. Note that, while the last sort item is by NID, the table display's click-sort overrides this (it sorts by updated date).
To eliminate Views itself as the culprit, I tried the same experiment, on yet another freshly-created site, with the Views Bulk Operations module enabled, but not used in the view. I was not able to reproduce repeated NIDs in the first 10 pages, nor a randomly selected set of other pages (although admittedly, I did not check all 240 pages in the view).
Comment #10
krystalcode commentedAdding here that I see the same with really low number of entities where only 1 or 2 of 3 items selected are processed. Therefore it is not an issue of processing a large number of items, and it is not a memory issue or environment issue - can be reproduced in different environments. As described, confirmation page displays correctly 3 items, but only 1 or 2 items are passed to the
executeMultiplemethod.Comment #11
krystalcode commentedIn my case I narrowed down the problem to the views query in the
populateQueueon the action processor return less results when called by the batch operation. Some of the selected entities are therefore not in the view results and they are filtered out. When I disable batch, the results are the correct. I commented out the code in that method that hooks alter hooks to eliminate the possibility that some other module would be altering the queue, same results.It is reproducible for me and the same entity in a set of 3 is skipped every time (not sure if it is the entity that matters or its position in the list). When I select that entity individually it is processed correctly.
I'm on
3.13so some code might have changed, but the problems looks the same.I don't know the architecture of the module well but I'm wondering, why are we making a database query again after the results have been selected? That opens a can of worms since there could be many uncontrolled reasons why the results could be different. I have selected the entities already and confirmed. Would it not be better to directly process the selected entities without filtering via the views results?
Comment #12
graber commentedI think there's one way we can push this forward: please add an automated test that fails. Once we'll have that it'll be reproducible and I can help.
Bumping to 4.1.x as I don't think this has been solved in the meanwhile.
Comment #13
krystalcode commentedOk thanks.
Meanwhile can I get a response to my question though as I want to understand how this works.
Comment #14
rossidrup commentedit happens to me too, all the time, 3-4 percent of items stay unprocessed...so I have to select the failed ones and do it again
Comment #15
super_romeo commented#14 same thing.
Interesting that occurs only when there are a few pages.
When there is only one page all is OK.
Comment #16
rossidrup commentedi cant use it on 1500 items....not possible i need to devide it in pages
Comment #17
graber commentedDid anything change in 4.1.3? There was a bug causing not all items to be processed when there are translations.
#3210957: VBO is skipping translated entities during batch process
Comment #18
rossidrup commentedyes I saw new release vir VBO...havent tried it yet...I will let you know
Comment #19
liquidcms commentedI last commented on this in Jan/22. Tried simple case today (4.1.2):
Std admin content page:
- filter by content type and language: gives me 92 items across 2 pages
- pick first page (50)
- select core action to Publish
- only runs on 28 items -> no errors.
Upgraded just now to 4.1.4. Rearan same test. Works as expected. Woo hoo!!
Comment #20
graber commentedThank you for checking this. Leaving the issue open as this definitely needs automated tests for multi-language content processing so this’ll never happen again.
Comment #21
grndlvl commentedWe are still experiencing the issue. It seems the same page results retrieved from
ViewsBulkOperationsActionProcessor::getPageList()is duplicated causing it to omit some items.Simplified example:
Page 9 has: 1, 2, 3, 4, 5, 6, 7
Page 13 will have: 3, 5, 6, 7, 8, 9, 10
I have debugged the page/offset/limit and sorting of the view and everything appears to be in order (with the exception of the return result set 0_0). This is very odd I am not sure why this might be happening yet.
Tried versions 4.0.0, 4.1.4, & 4.2.1.
Comment #22
jayelless commentedI have been experiencing what I believe is this same problem, which manifested itself as an error message:
Error: Typed property Drupal\views_bulk_operations\Action\ViewsBulkOperationsActionBase::$view must not be accessed before initialization in Drupal\vbo_export\Plugin\Action\VboExportBase->setHeader()that was generated when the code in ViewsBulkOperationsActionProcessor::populateQueue() executed a "return 0;" command prior to the end of the function (because it could not find any base field values), leaving the definition of the current view uninitialised in the plugin.
The basic cause of this is that the batch processing is expected to run for more than one iteration, but the unsorted nature of the results has allowed the results returned from query run in the batch processing initialisation to be less than a full batch as a consequence of the unspecified order of query results.
The problem was solved for me by adding a additional sort argument using the base entity id, which forced a fixed order every time the query was run.
Comment #23
jayelless commentedAs an additional comment. The problem did not exist with views_bulk_operations 8.x-3.4.
Comment #24
graber commentedInteresting.. I remember that ID sort was added sometime in the past but not 100% sure. Maybe it was accidentally removed at some point? Worth checking code in
ViewsBulkOperationsActionProcessorfrom 8.x-3.4.EDIT: No. Solution from #3020922: Overcome nondeterministic behaviour in mysql ORDER BY is in place as well as the missing translations fix from #3210957: VBO is skipping translated entities during batch process. There's always an ID sort (or it seems so). I'd start from checking if any case exists when that ID sort from
ViewsBulkOperationsActionProcessor::getPageList()is not applied if anyone wants to investigate on this.It'll be easier for those that can actually reproduce the issue on their environments as I can't.
Comment #25
grota commentedI think this is the way to reproduce it:
- create a view using a table style plugin.
- add some fields: at least a vbo field, configured to use batch, and a date field, used for the next point.
- configure the table style plugin to use a date field as default sorting option.
This should be enough.
The problem is in
ViewsBulkOperationsActionProcessor::getPageList.The workaround from 3020922 is nullified when it calls
$this->view->build();since it calls$this->style_plugin->buildSortPost()which in our case is inDrupal\views\Plugin\views\style\Table::buildSortPost()which in turn ends up callingDrupal\views\Plugin\views\field\EntityField->clickSort()which sets the order by statement based on the table's default sorting field.I don't know what a proper fix should be, but I hope the previous description can be useful to find one.
I have put the following workaround in place based on
hook_views_query_alter:As a note, I also tried an approach based on
hook_views_pre_executewithout success (probably because the query was already built).Comment #26
graber commentedHmm, can you try setting style plugin to
defaultjust before$this->view->build();in the action processor?$this->view->setHandler($this->bulkFormData['display_id'], 'style', 'default', []);(not sure about the last argument..).Comment #27
graber commentedok, more like
Please try.
Comment #28
grota commentedHi @Graber, sorry for the delay in answering. My proposed fix above had to be reverted because it actually introduced other regressions (incorrect elements on which ultimately the action is executed on) while selecting items across pages.
As soon as we'll be able to have another go at fixing the problem I'll let you know.
Comment #30
grota commentedHi @Graber,
I saw that you added those 2 lines in 22d6240fd295ec59bb758e8279046507fbbc528b. I tested them and they fixed the issue for me.
I created this MR to add a test.
As far as I know there are no other scenarios right now where the set of selected rows is incorrect, so for me this issue can be closed.
Comment #32
graber commentedTBH.. I accidentally added those lines in that commit, that should've been tested.. Oh well, I'm glad it worked and thank you for the test coverage!