omeka / omeka-s

Omeka S is a web publication system for universities, galleries, libraries, archives, and museums. It consists of a local network of independently curated exhibits sharing a collaboratively built pool of items, media, and their metadata.
GNU General Public License v3.0
398 stars 131 forks source link

Dispatching two jobs in a row causes error #2047

Open parijke opened 1 year ago

parijke commented 1 year ago

How to replicate:

Create a listener for api.update.pre

        $sharedEventManager->attach(
            ItemAdapter::class,
            'api.update.pre', // Do we need to get the pre or post events?
            [$this, 'dispatchJobs']
        );

Then in dispatchjobs, dispatch two times

    public function dispatchJobs(Event $event): void
    {
        $request = $event->getParam('request');
        $this->api = $this->getServiceLocator()->get('Omeka\ApiManager');
        /** @var Dispatcher $dispatcher */
        $dispatcher = $this->serviceLocator->get('Omeka\Job\Dispatcher');
          $dispatcher->dispatch(TestJob::class, [], $this->getServiceLocator()->get(Synchronous::class));
        $dispatcher->dispatch(TestJob::class, [], $this->getServiceLocator()->get(Synchronous::class));
        }

TestJob is just a job with an empty perform()

Error

Doctrine\ORM\ORMInvalidArgumentException
A new entity was found through the relationship 'Omeka\Entity\Job#owner' that was not configured to cascade persist operations for entity: Omeka\Entity\User@344. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'Omeka\Entity\User#__toString()' to get a clue.

Listening for the api.update.post event throws same error, even with one job

zerocrates commented 1 year ago

Can you include the traceback for that error?

parijke commented 1 year ago

Like this @zerocrates ?

Details:

Doctrine\ORM\ORMInvalidArgumentException: A new entity was found through the relationship 'Omeka\Entity\FulltextSearch#owner' that was not configured to cascade persist operations for entity: Omeka\Entity\User@344. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'Omeka\Entity\User#__toString()' to get a clue. in /app/vendor/doctrine/orm/lib/Doctrine/ORM/ORMInvalidArgumentException.php:97
Stack trace:
#0 /app/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php(3520): Doctrine\ORM\ORMInvalidArgumentException::newEntitiesFoundThroughRelationships(Array)
#1 /app/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php(390): Doctrine\ORM\UnitOfWork->assertThatThereAreNoUnintentionallyNonPersistedAssociations()
#2 /app/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php(392): Doctrine\ORM\UnitOfWork->commit(Object(Omeka\Entity\FulltextSearch))
#3 /app/application/src/Stdlib/FulltextSearch.php(43): Doctrine\ORM\EntityManager->flush(Object(Omeka\Entity\FulltextSearch))
#4 /app/application/Module.php(574): Omeka\Stdlib\FulltextSearch->save(Object(Omeka\Entity\Item), Object(Omeka\Api\Adapter\ItemAdapter))
#5 /app/vendor/laminas/laminas-eventmanager/src/EventManager.php(319): Omeka\Module->saveFulltext(Object(Laminas\EventManager\Event))
#6 /app/vendor/laminas/laminas-eventmanager/src/EventManager.php(171): Laminas\EventManager\EventManager->triggerListeners(Object(Laminas\EventManager\Event))
#7 /app/application/src/Api/Manager.php(323): Laminas\EventManager\EventManager->triggerEvent(Object(Laminas\EventManager\Event))
#8 /app/application/src/Api/Manager.php(269): Omeka\Api\Manager->finalize(Object(Omeka\Api\Adapter\ItemAdapter), Object(Omeka\Api\Request), Object(Omeka\Api\Response))
#9 /app/application/src/Api/Manager.php(136): Omeka\Api\Manager->execute(Object(Omeka\Api\Request))
#10 /app/application/src/Mvc/Controller/Plugin/Api.php(152): Omeka\Api\Manager->update('items', '18', Array, Array, Array)
#11 /app/application/src/Controller/Admin/ItemController.php(254): Omeka\Mvc\Controller\Plugin\Api->update('items', '18', Array, Array)
#12 /app/vendor/laminas/laminas-mvc/src/Controller/AbstractActionController.php(71): Omeka\Controller\Admin\ItemController->editAction()
#13 /app/vendor/laminas/laminas-eventmanager/src/EventManager.php(319): Laminas\Mvc\Controller\AbstractActionController->onDispatch(Object(Laminas\Mvc\MvcEvent))
#14 /app/vendor/laminas/laminas-eventmanager/src/EventManager.php(179): Laminas\EventManager\EventManager->triggerListeners(Object(Laminas\Mvc\MvcEvent), Object(Closure))
#15 /app/vendor/laminas/laminas-mvc/src/Controller/AbstractController.php(97): Laminas\EventManager\EventManager->triggerEventUntil(Object(Closure), Object(Laminas\Mvc\MvcEvent))
#16 /app/vendor/laminas/laminas-mvc/src/DispatchListener.php(132): Laminas\Mvc\Controller\AbstractController->dispatch(Object(Laminas\Http\PhpEnvironment\Request), Object(Laminas\Http\PhpEnvironment\Response))
#17 /app/vendor/laminas/laminas-eventmanager/src/EventManager.php(319): Laminas\Mvc\DispatchListener->onDispatch(Object(Laminas\Mvc\MvcEvent))
#18 /app/vendor/laminas/laminas-eventmanager/src/EventManager.php(179): Laminas\EventManager\EventManager->triggerListeners(Object(Laminas\Mvc\MvcEvent), Object(Closure))
#19 /app/vendor/laminas/laminas-mvc/src/Application.php(325): Laminas\EventManager\EventManager->triggerEventUntil(Object(Closure), Object(Laminas\Mvc\MvcEvent))
#20 /app/index.php(21): Laminas\Mvc\Application->run()
#21 {main}
zerocrates commented 1 year ago

Yes, like that.

Ultimately the problem here, I think, is going to be the call to clear() in the Synchronous job adapter... it's quite unlikely to work properly if you are doing more work after the job is over.

Are you looking to do code that's like this specifically, in that you'd explicitly fire off Synchronous jobs like in your test code? There's not much point to use the job system at all if you're forcing it to run synchronous.

parijke commented 1 year ago

The reason it was synchronous was for debugging purposes. It runs fine in background mode. Not sure that this is a bug or an expected result then.