You are here

function search_api_cron in Search API 8

Same name and namespace in other branches
  1. 7 search_api.module \search_api_cron()

Implements hook_cron().

This will first execute pending tasks (if there are any). After that, items will be indexed on all enabled indexes with a non-zero cron limit. Indexing will run for the time set in the cron_worker_runtime config setting (defaulting to 15 seconds), but will at least index one batch of items on each index.

3 calls to search_api_cron()
ServerTaskTest::testAddIndex in tests/src/Kernel/Server/ServerTaskTest.php
Tests task system integration for the server's addIndex() method.
ServerTaskTest::testDeleteItems in tests/src/Kernel/Server/ServerTaskTest.php
Tests task system integration for the server's deleteItems() method.
ServerTaskTest::testRemoveIndex in tests/src/Kernel/Server/ServerTaskTest.php
Tests task system integration for the server's removeIndex() method.

File

./search_api.module, line 58
Provides a rich framework for creating searches.

Code

function search_api_cron() {

  // Execute pending server tasks.
  \Drupal::getContainer()
    ->get('search_api.server_task_manager')
    ->execute();

  // Load all enabled, not read-only indexes.
  $conditions = [
    'status' => TRUE,
  ];
  $index_storage = \Drupal::entityTypeManager()
    ->getStorage('search_api_index');

  /** @var \Drupal\search_api\IndexInterface[] $indexes */
  $indexes = $index_storage
    ->loadByProperties($conditions);
  if (!$indexes) {
    return;
  }

  // Add items to the tracking system for all indexes for which this hasn't
  // happened yet.
  $task_manager = \Drupal::getContainer()
    ->get('search_api.task_manager');
  foreach ($indexes as $index_id => $index) {
    $conditions = [
      'type' => IndexTaskManager::TRACK_ITEMS_TASK_TYPE,
      'index_id' => $index_id,
    ];
    $task_manager
      ->executeSingleTask($conditions);

    // Filter out read-only indexes here, since we want to have tracking but not
    // index items for them.
    if ($index
      ->isReadOnly()) {
      unset($indexes[$index_id]);
    }
  }

  // Now index items.
  // Remember servers which threw an exception.
  $ignored_servers = [];

  // Continue indexing, one batch from each index, until the time is up, but at
  // least index one batch per index.
  $settings = \Drupal::config('search_api.settings');
  $default_cron_limit = $settings
    ->get('default_cron_limit');
  $end = time() + $settings
    ->get('cron_worker_runtime');
  $first_pass = TRUE;
  while (TRUE) {
    if (!$indexes) {
      break;
    }
    foreach ($indexes as $id => $index) {
      if (!$first_pass && time() >= $end) {
        break 2;
      }
      if (!empty($ignored_servers[$index
        ->getServerId()])) {
        continue;
      }
      $limit = $index
        ->getOption('cron_limit', $default_cron_limit);
      $num = 0;
      if ($limit) {
        try {
          $num = $index
            ->indexItems($limit);
          if ($num) {
            $variables = [
              '@num' => $num,
              '%name' => $index
                ->label(),
            ];
            \Drupal::service('logger.channel.search_api')
              ->info('Indexed @num items for index %name.', $variables);
          }
        } catch (SearchApiException $e) {

          // Exceptions will probably be caused by the server in most cases.
          // Therefore, don't index for any index on this server.
          $ignored_servers[$index
            ->getServerId()] = TRUE;
          $vars['%index'] = $index
            ->label();
          watchdog_exception('search_api', $e, '%type while trying to index items on %index: @message in %function (line %line of %file).', $vars);
        }
      }
      if (!$num) {

        // Couldn't index any items => stop indexing for this index in this
        // cron run.
        unset($indexes[$id]);
      }
    }
    $first_pass = FALSE;
  }
}