Update existing 'tmgmt_job_item' entity while changing the ID is not supported.

Created on 13 November 2023, 7 months ago
Updated 4 January 2024, 5 months ago

Problem/Motivation

Drupal\Core\Entity\EntityStorageException: Update existing 'tmgmt_job_item' entity while changing the ID is not supported. in Drupal\Core\Entity\Sql\SqlContentEntityStorage->save() (line 817 of core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php).
Drupal\Core\Entity\EntityStorageBase->save(Object) (Line: 806)
Drupal\Core\Entity\Sql\SqlContentEntityStorage->save(Object) (Line: 339)
Drupal\Core\Entity\EntityBase->save() (Line: 560)
Drupal\tmgmt\Entity\JobItem->setState(2, 'The translation of @source to @language is finished and can now be reviewed.', Array, 'status') (Line: 475)
Drupal\tmgmt\Entity\JobItem->needsReview('The translation of @source to @language is finished and can now be reviewed.', Array) (Line: 862)
Drupal\tmgmt\Entity\JobItem->addTranslatedData(Array) (Line: 496)
Drupal\tmgmt_deepl\Plugin\tmgmt\Translator\DeeplTranslator::batchFinished(1, Array, Array, '1 sec') (Line: 457)
_batch_finished() (Line: 99)
_batch_page(Object) (Line: 49)
Drupal\system\Controller\BatchController->batchPage(Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 592)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 121)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 182)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 704)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Steps to reproduce

  • Go to the source page
  • Select target language
  • Select an entity on review state or pending state
  • Request Translation

Proposed resolution

Preventing the addTranslatedData method from saving the entity if it no longer exists. Also handling the deletion of duplicate items and managing conflicting items in a more efficient manner. Additionally, combine the code with the getConflictingItemsMessage method in the JobForm.

πŸ› Bug report
Status

Needs review

Version

1.0

Component

Core

Created by

πŸ‡―πŸ‡΄Jordan Ahmad Khader

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @Ahmad Khader
  • πŸ‡―πŸ‡΄Jordan Ahmad Khader

    After a brief investigation of the issue, I discovered that the problem stems from the "Delete duplicates" functionality within the doBatchSubmit method in the JobCheckoutManager class.

    The issue arises because the JobCheckoutManager removes the job entity, and subsequently, the addTranslatedData method in the JobItem class attempts to update this entity in the database. However, the entity no longer exists in the database due to its removal by the JobCheckoutManager.

        // Delete duplicates.
        if ($existing_items_ids = $job->getConflictingItemIds()) {
          $item_storage = $this->entityTypeManager->getStorage('tmgmt_job_item');
          if (count($existing_items_ids) == $job->getItems()) {
            $this->messenger()->addStatus($this->t('All job items for job @label are conflicting, the job can not be submitted.', ['@label' => $job->label()]));
            return;
          }
          $item_storage->delete($item_storage->loadMultiple($existing_items_ids));
          $num_of_items = count($existing_items_ids);
          $this->messenger()->addWarning($this->getStringTranslation()->formatPlural($num_of_items, '1 conflicting item has been dropped for 
     job @label.', '@count conflicting items have been dropped for job @label.', ['@label' => $job->label()]));
        }
    

    The solution to address the issue is to restrict the addTranslatedData from saving the entity if it doesn't exist.

    The second improvement I made to the code is combining the getConflictingItemsMessage method in the JobForm message to make the message more clear and I'm considering the removal of this method due to the removal of duplicated jobitems before reaching it.

  • Status changed to Needs review 7 months ago
  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 9.5.x + Environment: PHP 7.3 & MySQL 8
    last update 7 months ago
    118 pass
  • πŸ‡¨πŸ‡­Switzerland Berdir Switzerland

    Hm, it's a bit unclear to me how this happens.

    Could we add test coverage for this somehow, we have some tests about the duplicate removals, see \Drupal\Tests\tmgmt\Functional\TMGMTCartTest::testCartEnforceSourceLanguage and \Drupal\Tests\tmgmt_config\Functional\ConfigSourceListTest::testViewTranslation() for example.

  • πŸ‡©πŸ‡ͺGermany aschiwi

    I had this issue and the patch fixed it for me, thank you for contributing!

  • πŸ‡ΉπŸ‡­Thailand AlfTheCat

    With much appreciation for the hard work on this issue, I can report that in my case there is still a loose end, as I am using tmgmt_openai to do automated translations and as a result, I have a huge number of jobs that are stuck at "in progress" but are not running ( πŸ’¬ Partially completed jobs items are not resumed/ completed on cron Active ).

    After applying the patch, I requested new translations for a node that is marked as "in progress" but for which translations are not actually running because the process either timed out before, or aborted due to this issue here. After patching, the translation runs without errors this time. However, it never seems to drop the old jobs so after the translation finishes, the node is still not translated and the translation status is again stuck at "in progress".

    It seems like I need to manually abort every single job that is stuck before being able to run it again, and if one of the languages fails, I need to abort again and lose the translations for the languages that were successful, until the whole operation succeeds. I understand I probably need to just do one language per node but that is going to take years :). As it is now, I am charged for multiple translations before I finally arrive at a fully translated node. I'm requesting 7 languages in one job and it's hit and miss.

    Perhaps my case is not entirely within the scope of this issue, but at least in case where there are translation jobs stuck at "in progress", this patch will fix the error but as it seems, it won't allow new translations to be accepted because it does not drop the old jobs before running the newly requested one.

Production build 0.69.0 2024