When attempting to run an RSS Feed import on cron, I am getting a fatal error. This appears to be due to the fact that the Feeds $entity->original returns null
Fatal error: Call to a member function hasTranslation() on null in /vagrant/web/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/ChangedItem.php on line 47 Call Stack: 0.0016 246608 1. {main}() /vagrant/web/index.php:0 0.0196 544288 2. Drupal\Core\DrupalKernel->handle() /vagrant/web/index.php:19 0.0554 1781704 3. Stack\StackedHttpKernel->handle() /vagrant/web/core/lib/Drupal/Core/DrupalKernel.php:652 0.0554 1781816 4. Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() /vagrant/web/vendor/stack/builder/src/Stack/StackedHttpKernel.php:23 0.0555 1782208 5. Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() /vagrant/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php:50 0.0555 1782640 6. Drupal\page_cache\StackMiddleware\PageCache->handle() /vagrant/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php:47 0.0555 1783144 7. Drupal\page_cache\StackMiddleware\PageCache->pass() /vagrant/web/core/modules/page_cache/src/StackMiddleware/PageCache.php:78 0.0555 1783224 8. Drupal\Core\StackMiddleware\KernelPreHandle->handle() /vagrant/web/core/modules/page_cache/src/StackMiddleware/PageCache.php:99 0.1101 2086200 9. Drupal\Core\StackMiddleware\Session->handle() /vagrant/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php:47 0.2719 2243832 10. Symfony\Component\HttpKernel\HttpKernel->handle() /vagrant/web/core/lib/Drupal/Core/StackMiddleware/Session.php:57 0.2719 2244688 11. Symfony\Component\HttpKernel\HttpKernel->handleRaw() /vagrant/web/vendor/symfony/http-kernel/HttpKernel.php:62 0.4059 4307336 12. call_user_func_array:{/vagrant/web/vendor/symfony/http-kernel/HttpKernel.php:139}() /vagrant/web/vendor/symfony/http-kernel/HttpKernel.php:139 0.4059 4307536 13. Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() /vagrant/web/vendor/symfony/http-kernel/HttpKernel.php:139 0.4059 4307784 14. Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() /vagrant/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php:97 0.4063 4319720 15. Drupal\Core\Render\Renderer->executeInRenderContext() /vagrant/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php:124 0.4063 4320168 16. Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() /vagrant/web/core/lib/Drupal/Core/Render/Renderer.php:574 0.4063 4320216 17. call_user_func_array:{/vagrant/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php:123}() /vagrant/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php:123 0.4063 4320912 18. Drupal\Core\Controller\FormController->getContentResult() /vagrant/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php:123 0.5736 5691264 19. Drupal\Core\Form\FormBuilder->buildForm() /vagrant/web/core/lib/Drupal/Core/Controller/FormController.php:74 0.5969 7997376 20. Drupal\Core\Form\FormBuilder->processForm() /vagrant/web/core/lib/Drupal/Core/Form/FormBuilder.php:314 0.6039 8157464 21. Drupal\Core\Form\FormSubmitter->doSubmitForm() /vagrant/web/core/lib/Drupal/Core/Form/FormBuilder.php:583 0.6039 8157576 22. Drupal\Core\Form\FormSubmitter->executeSubmitHandlers() /vagrant/web/core/lib/Drupal/Core/Form/FormSubmitter.php:51 0.6039 8158944 23. call_user_func_array:{/vagrant/web/core/lib/Drupal/Core/Form/FormSubmitter.php:111}() /vagrant/web/core/lib/Drupal/Core/Form/FormSubmitter.php:111 0.6039 8159088 24. Drupal\system\Form\CronForm->submitForm() /vagrant/web/core/lib/Drupal/Core/Form/FormSubmitter.php:111 0.6039 8159136 25. Drupal\ultimate_cron\ProxyClass\UltimateCron->run() /vagrant/web/core/modules/system/src/Form/CronForm.php:123 0.6059 8204248 26. Drupal\ultimate_cron\UltimateCron->run() /vagrant/web/modules/contrib/ultimate_cron/src/ProxyClass/UltimateCron.php:79 0.7333 11652544 27. Drupal\Core\Cron->processQueues() /vagrant/web/modules/contrib/ultimate_cron/src/UltimateCron.php:86 0.9210 15186352 28. Drupal\feeds\Plugin\QueueWorker\FeedProcess->processItem() /vagrant/web/core/lib/Drupal/Core/Cron.php:166 0.9213 15190888 29. Drupal\feeds\Plugin\QueueWorker\FeedProcess->finish() /vagrant/web/modules/contrib/feeds/src/Plugin/QueueWorker/FeedProcess.php:32 0.9213 15191280 30. Drupal\feeds\Entity\Feed->finishImport() /vagrant/web/modules/contrib/feeds/src/Plugin/QueueWorker/FeedProcess.php:60 0.9292 15372832 31. Drupal\Core\Entity\Entity->save() /vagrant/web/modules/contrib/feeds/src/Entity/Feed.php:280 0.9302 15425000 32. Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() /vagrant/web/core/lib/Drupal/Core/Entity/Entity.php:364 0.9311 15433880 33. Drupal\Core\Entity\EntityStorageBase->save() /vagrant/web/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:761 0.9311 15434024 34. Drupal\Core\Entity\ContentEntityStorageBase->doPreSave() /vagrant/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php:389 0.9313 15435744 35. Drupal\Core\Entity\EntityStorageBase->doPreSave() /vagrant/web/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php:291 0.9467 15866496 36. Drupal\Core\Entity\ContentEntityStorageBase->invokeHook() /vagrant/web/core/lib/Drupal/Core/Entity/EntityStorageBase.php:435 0.9467 15866840 37. Drupal\Core\Entity\ContentEntityStorageBase->invokeFieldMethod() /vagrant/web/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php:406 0.9512 15960968 38. Drupal\Core\Field\FieldItemList->preSave() /vagrant/web/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php:456 0.9512 15961288 39. Drupal\Core\Field\FieldItemList->delegateMethod() /vagrant/web/core/lib/Drupal/Core/Field/FieldItemList.php:202 0.9512 15961856 40. Drupal\Core\Field\Plugin\Field\FieldType\ChangedItem->preSave() /vagrant/web/core/lib/Drupal/Core/Field/FieldItemList.php:244
Comment | File | Size | Author |
---|---|---|---|
#18 | 2820548-cron-18.patch | 11.47 KB | andypost |
| |||
#18 | 2820548-interdiff-15.txt | 4.15 KB | andypost |
#15 | feeds-cron-deleted-feed-2820548-15.patch | 10.47 KB | MegaChriz |
|
Comments
Comment #2
handkerchiefSame problem with newest dev version of the module and core 8.3.3.
Comment #3
handkerchiefThe error apperas, after I deleted a feed.
And now: if i want to run cron:
Comment #4
luuph CreditAttribution: luuph as a volunteer commentedI debugged this a bit and it seems that the import job is kept in queue after deleting the feed. So the queue runs even for deleted Feeds.
Or actually as there is an exception then it's the Feed::finishImport() that runs for feed that doesn't exist.
Queue items seem to be deleted when deleting FeedType, but not when we delete the Feed itself.
Comment #5
eloivaque#4 Yes, feeds generate a row on queue mysql table.
My partial solution is removed all rows on queue table that relation feeds. Becareful wrong row if not related with feeds.
Comment #6
Anas_maw CreditAttribution: Anas_maw as a volunteer commentedAny updates here, this issue still exist on latest alpha1, drupal core 8.5.1
Comment #7
Anas_maw CreditAttribution: Anas_maw as a volunteer commentedIncreasing priority to critical as it's cause the cron to fail each time it's run.
Comment #8
MegaChriz CreditAttribution: MegaChriz as a volunteer commentedThis test should reproduce the reported error.
Comment #9
MegaChriz CreditAttribution: MegaChriz as a volunteer commentedUnserializing the task for deleted feed does not result into issues: the Feed instance can be unserialized safely, even if it refers to a non-existing feeds_feed entity. So a possible fix is to check if the feeds_feed entity still exists when initiating the queue task. The attached patch does this: In
FeedRefresh::processItem()
the code checks if the given feed entity still exists in the database. If it doesn't, it aborts.Comment #10
MegaChriz CreditAttribution: MegaChriz as a volunteer commentedRemoving
@group test
fromtestQueueAfterDeletingFeed()
.Comment #13
MegaChriz CreditAttribution: MegaChriz as a volunteer commentedAdjusted FeedRefreshTest to be aware of new parameter
$entity_type_manager
in the contructor method of FeedQueueWorkerBase.Comment #15
MegaChriz CreditAttribution: MegaChriz as a volunteer commentedFixed FeedQueueWorkerBaseTest + coding standard fixes.
Comment #16
Anas_maw CreditAttribution: Anas_maw as a volunteer commentedI have tried this patch, it's fixes the issue. But we need to implement a hook_update_N to fix existing data in queue table in the database.
Comment #17
MegaChriz CreditAttribution: MegaChriz as a volunteer commented@Anas_maw
I believe we don't need a hook_update_N here, because the queue worker checks if the Feed from the incoming data still exists. Thus queue tasks for no longer existing feeds would automatically get cleaned up after applying the patch.
Comment #18
andypostThis way queue item will store much less data & queue items will load real data when worker pick task
Also probably it needs update hook oh extra check that deserialized
$feed
is not object for BCLooks better to load each feed before execution, this way you may store feed_id and if load failed skip execution
are you sure that entity query is fastest way to make sure entity exists?
Comment #19
MegaChriz CreditAttribution: MegaChriz as a volunteer commented@andypost
Good idea to reduce the amount of information stored in a queue item. I cannot oversee yet if that change would break things though. Some information is temporary stored on the Feed entity when an import does not complete in one cron run. It *might* be restored properly when reloading the feed entity, but I'm not completely sure. There is no test coverage yet for an import task taking multiple cron runs to complete (a test like that could be ported from the D7 version of Feeds:
FeedsFileHTTPTestCase::testImportSourceWithMultipleCronRuns()
). I therefore propose to postpone your change suggestion to a follow-up. Do you agree?Comment #20
MegaChriz CreditAttribution: MegaChriz as a volunteer commented@andypost
No, I'm not entirely sure if it is the fastest way, but it would be faster than a full entity load. I took the code from
https://drupal.stackexchange.com/questions/223853/verify-a-node-with-a-g....
A direct database call would probably be faster, but it would also be less flexible. Right now the code could in theory also work for other entity types that implement
FeedInterface
.Comment #21
andypostI think no reason to split this issue into follow-up (optimization) better to add BC check for already queued items
Just have no idea which check is faster
is_scalar()
orinstanceof
Probably first is faster
Also entity load could use entity cache so result could be nearly the same as deserialization of job item
IMO the bug caused by storing entity which is orphaned(serialized) - so changing queue item fits into solution
Then you need custom data-object to serialize instead of feed or ID - that's purely job queue item data
I think better to add here another condition kinda is $feed a scalar and then load it
Comment #22
andypostFor this extra data better to port test cos it's not clear which data used to be stored in "entity" additionally
Probably I need to dig code deeper to get that
@MegaChriz can you point me to code which manipulate this data?
Comment #23
MegaChriz CreditAttribution: MegaChriz as a volunteer commented@andypost
Most of the temporary data on the feed entity is stored on State objects. These State objects are temporary stored on the feed entity on $feed->states and can be get by calling $feed->getState($stage) where $stage is the stage of the import: fetch, parse, process, etc.
These State objects are saved separately on Drupal's keyValue store as well, so these do not form a problem.
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.
Comment #24
andypostGot it! So yes this needs special test for "steped run"
Maybe just emulate it like a unit test which will check state after each time queue process item?
I'm sure that test should be at queue level instead of cron
Comment #25
MegaChriz CreditAttribution: MegaChriz as a volunteer commentedThe advantage of testing at the cron level (with a browser test) is that you can mimic the import process happening at two separate PHP processes. This way we can rule out that the import is working because something happens to be still in the static cache. The disadvantage is that it takes more time to write the test.
Comment #26
MegaChriz CreditAttribution: MegaChriz as a volunteer commented@andypost
Do you want to write a test that covers an import taking multiple cron runs to complete (aka an import happening in at least 2 separate PHP processes)? See
FeedsFileHTTPTestCase::testImportSourceWithMultipleCronRuns()
for the D7 version.Comment #27
andypost@MegaChriz I will try this weekend
Comment #28
MegaChriz CreditAttribution: MegaChriz as a volunteer commented@andypost
Cool, thanks in advance.
Some details about how a similar test was developed in D7:
sleep(1);
For the above process to work in D8 there is one extra challenge though: each item to process is a queue task by itself. So to import 10 items, you'll end up with 12 queue tasks. One for fetching, one for parsing and 10 for processing. If the parse limit is brought down to 5 (the default is 50), it will be 13 queue tasks (two for parsing). In the D7 version of Feeds it is 1 queue task for importing 10 items with the default settings and with a parse limit of 5 it is 2 queue tasks.
Comment #29
Anas_maw CreditAttribution: Anas_maw as a volunteer commentedThe patch in #18 give me the following errors when run cron:
array_flip(): Can only flip STRING and INTEGER values! EntityStorageBase.php:227 [warning]
Object of class Drupal\feeds\Entity\Feed could not be converted to string ContentEntityStorageBase.php:1020 [error]
I have imported 100000 user throw feeds, i have 80000 row in queue table for feeds.
-When applying the patch in #15 the queue table row number increased and decreased.
-When applying the patch in #18 the queue table row number not changed.
Comment #30
m.abdulqader CreditAttribution: m.abdulqader at Sprintive commented+1
Comment #31
MegaChriz CreditAttribution: MegaChriz as a volunteer commented@andypost
Do you think you have time soon to work on the test? I would like to make a new release of Feeds in about two weeks, preferable with this fix in it. (Sorry if this makes you feel pushed, not sure how to formulate the question differently.)
Comment #33
MegaChriz CreditAttribution: MegaChriz as a volunteer commentedCommitted #15 because I want to include a fix for this in the next release. The optimizations done by @andypost will be postponed to a follow-up which I will create an issue for shortly.
Comment #34
MegaChriz CreditAttribution: MegaChriz as a volunteer commented@andypost
I opened a follow-up: #2978490: Optimize Feeds queue
Comment #36
jjwfcd CreditAttribution: jjwfcd commentedagain the issue
the newest drupal 8.7.8 and feeds version 8.3.x-alapha6
below is the error output, than you guys for help!
[error] Error: Call to a member function getPlugins() on null in Drupal\feeds\Entity\Feed->preSave() (line 512 of /var/www/html/docroot/modules/contrib/feeds/src/Entity/Feed.php) #0 /var/www/html/docroot/core/lib/Drupal/Core/Entity/EntityStorageBase.php(499): Drupal\feeds\Entity\Feed->preSave(Object(Drupal\feeds\FeedStorage))
#1 /var/www/html/docroot/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php(692): Drupal\Core\Entity\EntityStorageBase->doPreSave(Object(Drupal\feeds\Entity\Feed))
#2 /var/www/html/docroot/core/lib/Drupal/Core/Entity/EntityStorageBase.php(454): Drupal\Core\Entity\ContentEntityStorageBase->doPreSave(Object(Drupal\feeds\Entity\Feed))
#3 /var/www/html/docroot/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php(838): Drupal\Core\Entity\EntityStorageBase->save(Object(Drupal\feeds\Entity\Feed))
#4 /var/www/html/docroot/core/lib/Drupal/Core/Entity/EntityBase.php(394): Drupal\Core\Entity\Sql\SqlContentEntityStorage->save(Object(Drupal\feeds\Entity\Feed))
#5 /var/www/html/docroot/modules/contrib/feeds/src/FeedImportHandler.php(305): Drupal\Core\Entity\EntityBase->save()
#6 /var/www/html/docroot/modules/contrib/feeds/src/Entity/Feed.php(260): Drupal\feeds\FeedImportHandler->startCronImport(Object(Drupal\feeds\Entity\Feed))
#7 /var/www/html/docroot/modules/contrib/feeds/feeds.module(90): Drupal\feeds\Entity\Feed->startCronImport()
#8 [internal function]: feeds_cron()
#9 /var/www/html/docroot/core/lib/Drupal/Core/Extension/ModuleHandler.php(392): call_user_func_array('feeds_cron', Array)
#10 /var/www/html/docroot/core/lib/Drupal/Core/Cron.php(236): Drupal\Core\Extension\ModuleHandler->invoke('feeds', 'cron')
#11 /var/www/html/docroot/core/lib/Drupal/Core/Cron.php(134): Drupal\Core\Cron->invokeCronHandlers()
#12 /var/www/html/docroot/core/lib/Drupal/Core/ProxyClass/Cron.php(75): Drupal\Core\Cron->run()
#13 /var/www/html/vendor/drush/drush/src/Drupal/Commands/core/DrupalCommands.php(59): Drupal\Core\ProxyClass\Cron->run()
#14 [internal function]: Drush\Drupal\Commands\core\DrupalCommands->cron(Array)
#15 /var/www/html/vendor/consolidation/annotated-command/src/CommandProcessor.php(257): call_user_func_array(Array, Array)
#16 /var/www/html/vendor/consolidation/annotated-command/src/CommandProcessor.php(212): Consolidation\AnnotatedCommand\CommandProcessor->runCommandCallback(Array, Object(Consolidation\AnnotatedCommand\CommandData))
#17 /var/www/html/vendor/consolidation/annotated-command/src/CommandProcessor.php(176): Consolidation\AnnotatedCommand\CommandProcessor->validateRunAndAlter(Array, Array, Object(Consolidation\AnnotatedCommand\CommandData))
#18 /var/www/html/vendor/consolidation/annotated-command/src/AnnotatedCommand.php(302): Consolidation\AnnotatedCommand\CommandProcessor->process(Object(Symfony\Component\Console\Output\ConsoleOutput), Array, Array, Object(Consolidation\AnnotatedCommand\CommandData))
#19 /var/www/html/vendor/symfony/console/Command/Command.php(255): Consolidation\AnnotatedCommand\AnnotatedCommand->execute(Object(Drush\Symfony\DrushArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#20 /var/www/html/vendor/symfony/console/Application.php(1000): Symfony\Component\Console\Command\Command->run(Object(Drush\Symfony\DrushArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))#21 /var/www/html/vendor/symfony/console/Application.php(255): Symfony\Component\Console\Application->doRunCommand(Object(Consolidation\AnnotatedCommand\AnnotatedCommand), Object(Drush\Symfony\DrushArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#22 /var/www/html/vendor/symfony/console/Application.php(148): Symfony\Component\Console\Application->doRun(Object(Drush\Symfony\DrushArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#23 /var/www/html/vendor/drush/drush/src/Runtime/Runtime.php(118): Symfony\Component\Console\Application->run(Object(Drush\Symfony\DrushArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#24 /var/www/html/vendor/drush/drush/src/Runtime/Runtime.php(49): Drush\Runtime\Runtime->doRun(Array, Object(Symfony\Component\Console\Output\ConsoleOutput))
#25 /var/www/html/vendor/drush/drush/drush.php(72): Drush\Runtime\Runtime->run(Array)
#26 /var/www/html/vendor/drush/drush/includes/preflight.inc(18): require('/var/www/html/w...')
#27 phar:///usr/local/bin/drush/bin/drush.php(141): drush_main()
#28 /usr/local/bin/drush(10): require('phar:///usr/loc...')
#29 {main}.
Comment #37
bogdog400 CreditAttribution: bogdog400 commentedBTW, I deleted a bunch of modules to clean up a dev site and now I'm getting this cron error with version 8.9.3 of Drupal.