This is a follow-up to #2820548: Fatal error when triggering Feeds via cron .
Problem/Motivation
Right now the entire feed object is serialized when queuing an import task for a feed. As a feed entity can be potentially big this could be a waste of database space in the queue. It can also cause PHP errors when certain information on the feed is outdated, for example if it contains references to no longer existing objects.
There's only one problem to this: besides the State objects on the feed, it is uncertain exactly which data on the feed is necessary during the various stages of import and therefore it is uncertain if reloading the feed entity from the database instead of storing it entirely and then unserializing it will cause issues.
About State objects
A feed import task is monitored by using State objects. A State object holds information about how many items were inserted, updated, deleted, skipped, etc. These State objects are only temporary apparent on a feed entity (on $feed->states) and saved on Drupal's key-value store after each queue task is done. When loading a feed queue task the State objects are taken from Drupal's key-value store again. In other words: State objects are always regenerated when unserializing a feed entity.
From #2820548-23: Fatal error when triggering Feeds via cron :
It could be that these State objects are everything what is stored temporary and in that case there is no issue with reducing the amount of data on the queue. But since there's a lot of code in Feeds, I cannot be sure of that and because of that we'd better have a test that covers the import process that needs multiple cron runs to complete.
Proposed resolution
To reduce the data in the queue, the solution would be to store only the feed ID on the queue task.
To ensure this doesn't cause issues for the import task, we need an automated test that covers the following case: running an import task that takes multiple cron runs to complete. Or, alternatively, ensure in any other way that an import process works using two (or more) separate PHP processes.
The reason we need two (or more) separate PHP processes for the import task is to rule out that the import is working because something happens to be still in the static cache.
Implementing the test happens in #3044983: Add test coverage for importing using multiple cron runs.
Remaining tasks
- #3044983: Add test coverage for importing using multiple cron runs DONE
If possible, only store the feed ID on the queue task instead of the whole feed entity (the test results should reveal that this doesn't introduce issues).DONEBackwards compatibility: In \Drupal\feeds\Plugin\QueueWorker\FeedsRefresh, take into account that existing queue tasks may have a full feed entity serialized.DONEBackwards compatibility: In \Drupal\feeds\Plugin\QueueWorker\FeedsRefresh, take into account that existing queue tasks may have a full feed entity serialized that no longer exists.DONEWrite a test that ensures that queue tasks with a full serialized feed entity can be processed and don't remain on the queue forever.DONE
API changes
To be determined.
Data model changes
When queuing a feed for import, only the feed ID will be stored on the queue task.
| Comment | File | Size | Author |
|---|
Issue fork feeds-2978490
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
megachrizThis patch was posted by @andypost in #2820548-18: Fatal error when triggering Feeds via cron (it was called 2820548-interdiff-15.txt there) and can be used as a start for this issue.
Comment #4
megachrizComment #5
andypostWould be great to fit in a4
Comment #6
andypostComment #7
megachriz@andypost
That would be great indeed. But because I would like to make a new release in the next few days and I think I won't have time to write the test before that, it is more likely to get in alpha5 than in alpha4.
Comment #8
mshdevx commentedBefore applying this patch need to run update, which will delete all existing feeds queues with old logic of data storing. Because these queues will fail all the time and will never processed.
Comment #9
andypostI think it could be done in BC way, checking that queue item is integer (scalar) or feedItemInterface
Comment #10
mshdevx commented@andypost, but then queues with objects will never processed and deleted from queue table. And each cron run will try to process them again
Comment #11
megachriz@maxdev
I think @andypost is right and it can be done in a BC way without getting items stuck on the queue. It's already listed on the remaining tasks that this BC layer must be added.
It would be useful to write a test for this case too.
Comment #12
megachrizI've opened #3044983: Add test coverage for importing using multiple cron runs. I thought it was handier to split that task out of this one. Test coverage for that multiple cron runs case is probably handy to have for other issues as well.
We still need other automated tests here though, like one that checks if a full serialized feed entity can be processed (for backwards compatibility).
Comment #13
andypostNot clear where to add tests
Comment #14
megachriz@andypost
I think in tests/src/Kernel? Or in Drupal\Tests\feeds\Functional\QueueTest?
Comment #15
joelpittetNext steps:
Comment #18
ramil g commentedThis line was in testBeginStage() in FeedRefreshTest.php
$this->plugin->processItem(NULL);I'm not sure what this was supposed to do, but I had to delete it because in the processItem function in FeedRefresh.php, it was giving me this error when running the test
and part of the reason is that feedLoad was setup to always return a mock feed.
Comment #19
joelpittet@ramil g and I looked at this last night, it is related to the patch, but we need to figure out where to either trigger or trip that error to occur in the new setup.
feeds/src/Entity/Feed.php:194inside\Drupal\feeds\Entity\Feed::getTypeprobably needs a spurious call to getType() at the start of the batch process or something.Comment #20
megachrizRe #18
Taken from commit 238b4c15, this is what the test
testBeginStage()originally looked like:And this is what
FeedRefresh::processItem()looked like back then:So I think that the test wanted the cover the case that the process is aborted gracefully when the value that is passed is not an object implementing FeedInterface. So from
processItem()above, coverage for the following code:I think the line
$this->plugin->processItem(NULL);should go into a separate test method and cover the code above: aborting when the feed is not an instance of FeedInterface.Comment #21
megachrizI think I've addressed all remaining tasks. If this passes tests, then this thing is ready for review!
Comment #22
andileco commentedI tested MR !66, and it worked well for me and caused no errors. +1 to committing.
Comment #24
megachrizThanks for testing, @andileco :).
This is now merged.