Infinite recursion if there is a search_api task in the database.

Created on 9 May 2025, about 1 month ago

Problem/Motivation

There is an infinite recursion when indexing if there is a `updateIndex` command in the search_api_tasks table. I'm not sure if the same issue applies to other possible task types.

This leads to PHP eventually running out of memory.

Steps to reproduce

Here is how I was able to replicate this issue. Saving a index triggers postSave():
\Drupal::entityTypeManager()->getStorage('search_api_index')->load('job_listings')->save()

Index::postSave() calls Index::reactToServerSwitch(), which instructs the server instance to update the index (in case it has changed) by calling Server::updateIndex(). If the connection to the server fails, Server::updateIndex() creates a search_api task by calling TaskManager::addTask().

I replicated the failure by modifying Server::updateIndex() like this:

diff --git i/src/Entity/Server.php w/src/Entity/Server.php
index 6e3867ec..09d5caeb 100644
--- i/src/Entity/Server.php
+++ w/src/Entity/Server.php
@@ -295,6 +295,7 @@ class Server extends ConfigEntityBase implements ServerInterface {
     $server_task_manager = \Drupal::getContainer()->get('search_api.server_task_manager');
     try {
       if ($server_task_manager->execute($this)) {
+        throw new SearchApiException("some failure");
         $this->getBackend()->updateIndex($index);
         return;
       }

Now, a search_api task is created. Then, I can trigger the bug by running `drush sapi-i`.

Here is a stack trace from the crash:

[...]
> #190459 [internal function]: Drupal\search_api\Task\ServerTaskManager->processEvent()
> #190460 /var/www/html/public/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func()
> #190461 /var/www/html/public/modules/contrib/search_api/src/Task/TaskManager.php(212): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
> #190462 /var/www/html/public/modules/contrib/search_api/src/Task/TaskManager.php(264): Drupal\search_api\Task\TaskManager->executeSpecificTask()
> #190463 /var/www/html/public/modules/contrib/search_api/src/Task/ServerTaskManager.php(95): Drupal\search_api\Task\TaskManager->executeAllTasks()
> #190464 /var/www/html/public/modules/contrib/search_api/src/Entity/Server.php(424): Drupal\search_api\Task\ServerTaskManager->execute()
> #190465 /var/www/html/public/modules/contrib/search_api/src/Entity/Index.php(1222): Drupal\search_api\Entity\Server->deleteAllIndexItems()
> #190466 /var/www/html/public/modules/contrib/elasticsearch_connector/src/SearchAPI/BackendClient.php(236): Drupal\search_api\Entity\Index->clear()
> #190467 /var/www/html/public/modules/contrib/elasticsearch_connector/src/Plugin/search_api/backend/ElasticSearchBackend.php(455): Drupal\elasticsearch_connector\SearchAPI\BackendClient->updateIndex()
> #190468 /var/www/html/public/modules/contrib/search_api/src/Task/ServerTaskManager.php(160): Drupal\elasticsearch_connector\Plugin\search_api\backend\ElasticSearchBackend->updateIndex()
> #190469 /var/www/html/public/modules/contrib/search_api/src/Task/ServerTaskManager.php(115): Drupal\search_api\Task\ServerTaskManager->executeTask()
> #190470 [internal function]: Drupal\search_api\Task\ServerTaskManager->processEvent()
> #190471 /var/www/html/public/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func()
> #190472 /var/www/html/public/modules/contrib/search_api/src/Task/TaskManager.php(212): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
> #190473 /var/www/html/public/modules/contrib/search_api/src/Task/TaskManager.php(264): Drupal\search_api\Task\TaskManager->executeSpecificTask()
> #190474 /var/www/html/public/modules/contrib/search_api/src/Task/ServerTaskManager.php(95): Drupal\search_api\Task\TaskManager->executeAllTasks()
> #190475 /var/www/html/public/modules/contrib/search_api/src/Entity/Server.php(424): Drupal\search_api\Task\ServerTaskManager->execute()
> #190476 /var/www/html/public/modules/contrib/search_api/src/Entity/Index.php(1222): Drupal\search_api\Entity\Server->deleteAllIndexItems()
> #190477 /var/www/html/public/modules/contrib/elasticsearch_connector/src/SearchAPI/BackendClient.php(236): Drupal\search_api\Entity\Index->clear()
> #190478 /var/www/html/public/modules/contrib/elasticsearch_connector/src/Plugin/search_api/backend/ElasticSearchBackend.php(455): Drupal\elasticsearch_connector\SearchAPI\BackendClient->updateIndex()
> #190479 /var/www/html/public/modules/contrib/search_api/src/Task/ServerTaskManager.php(160): Drupal\elasticsearch_connector\Plugin\search_api\backend\ElasticSearchBackend->updateIndex()
> #190480 /var/www/html/public/modules/contrib/search_api/src/Task/ServerTaskManager.php(115): Drupal\search_api\Task\ServerTaskManager->executeTask()
> #190481 [internal function]: Drupal\search_api\Task\ServerTaskManager->processEvent()
> #190482 /var/www/html/public/core/lib/Drupal/Component/EventDispatcher/ContainerAwareEventDispatcher.php(111): call_user_func()
> #190483 /var/www/html/public/modules/contrib/search_api/src/Task/TaskManager.php(212): Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch()
> #190484 /var/www/html/public/modules/contrib/search_api/src/Task/TaskManager.php(264): Drupal\search_api\Task\TaskManager->executeSpecificTask()
> #190485 /var/www/html/public/modules/contrib/search_api/src/Task/ServerTaskManager.php(95): Drupal\search_api\Task\TaskManager->executeAllTasks()
> #190486 /var/www/html/public/modules/contrib/search_api/src/Entity/Server.php(359): Drupal\search_api\Task\ServerTaskManager->execute()
> #190487 /var/www/html/public/modules/contrib/search_api/src/Entity/Index.php(1045): Drupal\search_api\Entity\Server->indexItems()
> #190488 /var/www/html/public/modules/contrib/search_api/src/Entity/Index.php(974): Drupal\search_api\Entity\Index->indexSpecificItems()
> #190489 /var/www/html/public/modules/contrib/search_api/src/IndexBatchHelper.php(160): Drupal\search_api\Entity\Index->indexItems()
> #190490 /var/www/html/vendor/drush/drush/includes/batch.inc(257): Drupal\search_api\IndexBatchHelper::process()
> #190491 /var/www/html/vendor/drush/drush/includes/batch.inc(204): _drush_batch_worker()
> #190492 /var/www/html/vendor/drush/drush/includes/batch.inc(75): _drush_batch_command()
> #190493 /var/www/html/vendor/drush/drush/src/Commands/core/BatchCommands.php(25): drush_batch_command()
> #190494 [internal function]: Drush\Commands\core\BatchCommands->process()
> #190495 /var/www/html/vendor/consolidation/annotated-command/src/CommandProcessor.php(276): call_user_func_array()
> #190496 /var/www/html/vendor/consolidation/annotated-command/src/CommandProcessor.php(212): Consolidation\AnnotatedCommand\CommandProcessor->runCommandCallback()
> #190497 /var/www/html/vendor/consolidation/annotated-command/src/CommandProcessor.php(175): Consolidation\AnnotatedCommand\CommandProcessor->validateRunAndAlter()
> #190498 /var/www/html/vendor/consolidation/annotated-command/src/AnnotatedCommand.php(387): Consolidation\AnnotatedCommand\CommandProcessor->process()
> #190499 /var/www/html/vendor/symfony/console/Command/Command.php(326): Consolidation\AnnotatedCommand\AnnotatedCommand->execute()
> #190500 /var/www/html/vendor/symfony/console/Application.php(1096): Symfony\Component\Console\Command\Command->run()
> #190501 /var/www/html/vendor/symfony/console/Application.php(324): Symfony\Component\Console\Application->doRunCommand()
> #190502 /var/www/html/vendor/symfony/console/Application.php(175): Symfony\Component\Console\Application->doRun()
> #190503 /var/www/html/vendor/drush/drush/src/Runtime/Runtime.php(110): Symfony\Component\Console\Application->run()
> #190504 /var/www/html/vendor/drush/drush/src/Runtime/Runtime.php(40): Drush\Runtime\Runtime->doRun()

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

🐛 Bug report
Status

Active

Version

8.0

Component

Code

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

Comments & Activities

Production build 0.71.5 2024