Starting batch operations from hook_node_update() When importing content using Feeds using an importer associated with a node type, the mapping can be configured to assign taxonomy terms from the Feed Node to the imported Feed Items. On a project, we need to extend this feature by also updating all the already imported Feed Items when a Feed Node is updated.

This can be done using hook_node_update($node). But since a single Feed Node can have a lot of Feed Items, they cannot be all updated in a single HTTP request otherwise we may encounter a timeout. The obvious way to avoid timeouts, is to use the Batch operations API.

Most of the time, hook_node_update() implementations will be executed because node_save has been called from a form submit handler, therefore, most of the time, there is no need to call batch_process from a hook_node_update() since it will be called automatically at the end of the form processing. Calling batch_progress from hook_node_update()  may also produce unexpected result since it will prevent other implementation of the same hook or others hooks to be executed.

But what about the times when the hook_node_update() implementations are not executed from a form submit handler. For instance, when node_save is called from an implementation of hook_cron? Is there a way to detect these cases to either run all the update at once or delay them to a dedicated queue?
As pointed in kiamlaluno's answer, there is no execution context information passed to hook_node_update() implementations. So we ended up using debug_backtrace() to look up for the currently processed form (if any). If a form is processed, drupal_process_form() will handle batch processing for us. If not, we can't safely start a progressive processing of the batch. But we can run the whole batch in a single pass. This can lead to timeout and should really be replaced. Either by delaying operations execution (queued operations) or by starting progressive processing of the batch after all update hook have been run (but how ?).

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

function MODULE_node_update($node) {
  if (some_condition_on($node)) {
    $batch = array(
      'operations' =&gt; 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 =&amp; batch_get();
      $batch['progressive'] = FALSE;
      batch_process();
    }
  }
}