Запуск пакетных операций из обновления узла подключения()


При импорте контента с использованием каналов с использованием импортера, связанного с типом узла, сопоставление может быть настроено для назначения терминов таксономии из узла канала импортированным элементам канала. В проекте нам нужно расширить эту функцию, также обновив все уже импортированные элементы ленты при обновлении узла ленты.

Это можно сделать с помощью hook_node_update($node). Но так как один Узел подачи может иметь много элементов ленты , все они не могут быть обновлены в одном HTTP-запросе, иначе мы можем столкнуться с таймаутом. Очевидный способ избежать тайм-аутов - использовать API пакетных операций .

Большую часть времени реализации hook_node_update() будут выполняться, потому что node_save был вызван из обработчика отправки формы, поэтому в большинстве случаев нет необходимости вызывать batch_process из hook_node_update(), поскольку он будет вызван автоматически в конце обработки формы. Вызов batch_progress из hook_node_update() также может привести к неожиданному результату, поскольку это предотвратит выполнение другой реализации того же крючка или других крючков.

Но как насчет случаев, когда реализации hook_node_update() не выполняются из обработчика отправки формы. Например, когда node_save вызывается из реализации hook_cron? Есть ли способ обнаружить эти случаи, чтобы либо запустить все обновления сразу, либо отложить их в выделенную очередь?

Author: Pierre Buyle, 2011-04-26

2 answers

Как указано в ответе киамлалуно, информация о контексте выполнения не передается в реализации hook_node_update(). Таким образом, мы закончили тем, что использовали debug_backtrace() для поиска текущей обработанной формы (если таковая имеется). Если форма обработана, drupal_process_form() будет обрабатывать пакетную обработку для нас. Если нет, мы не сможем безопасно начать постепенную обработку пакета. Но мы можем запустить всю партию за один проход. Это может привести к тайм-ауту и действительно должно быть заменено. Либо путем задержки выполнения операций ( в очереди операции) или путем запуска последовательной обработки пакета после выполнения всех операций обновления (но как?).

function _MODULE_get_currently_processed_form() {
  $backtrace = debug_backtrace();
  while ($frame = next($backtrace)) {
    if (isset($frame['function']) && $frame['function'] == 'drupal_process_form') {
      return array(
        'form_id' => $frame['args'][0],
        'form' => &$frame['args'][1],
        'form_state' => &$frame['args'][2],
      );
    }
  }
  return FALSE;
}

function MODULE_node_update($node) {
  if (some_condition_on($node)) {
    $batch = array(
      'operations' => array(
        // ...
      ),
    );
    batch_set($batch);
    $currently_processed_form = _MODULE_get_currently_processed_form();
    if (!$currently_processed_form) {
      // We are not currently processing a form, the batch processing won't be
      // automatically started. But we cannot start processing it because it
      // will end the request and prevent any other post node update code to
      // run. So we process the batch in a single pass and hope for the best.
      // FIXME: Start progressive processing of the batch after node update
      // processing (using hook_exit?) or use other delayed execution (using
      // queued operation?)
      $batch =& batch_get();
      $batch['progressive'] = FALSE;
      batch_process();
    }
  }
}
 1
Author: Pierre Buyle, 2011-06-01 06:28:07

Короче говоря, невозможно узнать, какая функция вызвала реализацию крючка; крючок не получает аргумент, который, например, равен TRUE, когда крючок вызывается из обработчика отправки формы и FALSE, когда вызов крючка вызван из другой реализации крючка.

Как правило, лучше запускать пакетные операции из обратного вызова меню, а не из функции, которая вызывается, например, во время задач cron, когда Drupal не выводит страницу в браузер. В на самом деле, чтобы избежать тайм-аутов PHP, Drupal заставляет браузер вызывать обратный вызов пакетного меню каждые X секунд; если в нем не задействован браузер (как это происходит с задачами cron, выполняемыми из утилиты cron), то пакетные операции не работают или работают как обычный вызов функции, который может вызвать тайм-ауты PHP.
Это исключает возможность использования пакетной операции в вашем случае.

Если вам действительно нужно использовать пакетные операции, то вы должны делать то, что делает основной код Drupal. Когда модуль необходимо использовать пакетные операции, он сообщает, что в реализации hook_requirements(), которая предоставляет пользователю ссылку на страницу, с которой начинаются пакетные операции. В качестве альтернативы аналогичное предупреждающее сообщение может быть размещено на странице административных настроек; также в этом случае пользователь начнет пакетные операции, нажав на ссылку, указанную в сообщении.

То, что я сообщал ранее о пакетных операциях, все еще актуально: пакетные операции зависят от браузера. Если есть проблемы с подключением к серверу или сбой браузера, пакетные операции будут прерваны; это также происходит, если компьютер, на котором запущен браузер, зависает или выключается/сбрасывается по какой-либо причине.
Пакетные операции следует использовать для относительно длительных операций, но не для операций, которые длятся 20-30 и более минут.

 0
Author: kiamlaluno, 2011-04-27 12:01:27