User login

Batch API process silently fails if function in file not in default Drupal bootstrap isn't explicitly included

<?php
function _batch_process() {
 
$batch =& batch_get();
 
$current_set =& _batch_current_set();
 
$set_changed = TRUE;

  if (

$batch['progressive']) {
   
timer_start('batch_processing');
  }

  while (!

$current_set['success']) {
   
// If this is the first time we iterate this batch set in the current
    // request, we check if it requires an additional file for functions
    // definitions.
   
if ($set_changed && isset($current_set['file']) && is_file($current_set['file'])) {
      include_once(
$current_set['file']);
    }

   

$finished = 1;
   
$task_message = '';
list(
$function, $args) = reset($current_set['operations']);
drupal_set_message('f: <pre>'.var_export($function,TRUE).'</pre>');
$huh = function_exists($function);
drupal_set_message('<pre>'.var_export($huh,TRUE).'</pre>');
    if ((list(
$function, $args) = reset($current_set['operations'])) && function_exists($function)) {
?>

Moral of the story: When dealing with batch, assume that the callback functions for operations will not be in scope.

Pro Drupal Development says this:

file: If the callback functions for operations and finished are not in scope during a normal Drupal request, the path of the file containing these functions must be given. The path is relative to the base_path() of the Drupal installation and can be conveniently built using drupal_get_path(). It is unnecessary to define file if the functions are already in scope.

The big huge addendum here is that even if your function is defined in the same file as the function calling batch, it is not necessarily in scope.

This is a conditionally included file so it must be added specially.

This was wasted a lot of time. A not-in-scope error message would be helpful.

I think i spent 12 hours discovering batch processes need code files manually added / specially called, even if the function is defined in the very same file as the function calling batch!

Their sample batch processing functions from http://api.drupal.org/api/group/batch/6 sort of re-worked to actually call each other and to have a 'file' definition:

<?php
function agaric_example_module_parse(&$parameter1, $parameter2 = 0) {
 
$batch = array(
'title' => t('Test Exporting'),
'operations' => array(
array(
'my_function_1', array($parameter1, 'story')),
// array('my_function_2', array()),
),
'file' => drupal_get_path('module', 'agaric_example_module') . '/conditional.inc',
'finished' => 'batch_test_finished',
);
batch_set($batch);
// only needed if not inside a form _submit handler :
batch_process();

}

function

my_function_1($uid, $type, &$context) {
// The $context array gathers batch context information about the execution (read),
  // as well as 'return values' for the current operation (write)
  // The following keys are provided :
  // 'results' (read / write): The array of results gathered so far by
  //   the batch processing, for the current operation to append its own.
  // 'message' (write): A text message displayed in the progress page.
  // The following keys allow for multi-step operations :
  // 'sandbox' (read / write): An array that can be freely used to
  //   store persistent data between iterations. It is recommended to
  //   use this instead of $_SESSION, which is unsafe if the user
  //   continues browsing in a separate window while the batch is processing.
  // 'finished' (write): A float number between 0 and 1 informing
  //   the processing engine of the completion level for the operation.
  //   1 (or no value explicitly set) means the operation is finished
  //   and the batch processing can continue to the next operation.
$node = node_load(array('uid' => $uid, 'type' => $type));
$context['results'][] = $node->nid .' : '. $node->title;
$context['message'] = $node->title;
}

function

batch_test_finished($success, $results, $operations) {
  if (
$success) {
   
$message = format_plural(count($results), 'One post processed.', '@count posts processed.');
  }
  else {
   
$message = t('Finished with an error.');
  }
drupal_set_message($message);
// Providing data for the redirected page is done through $_SESSION.
 
foreach ($results as $result) {
   
$items[] = t('Loaded node %title.', array('%title' => $result));
  }
 
$_SESSION['my_batch_results'] = $items;
}
?>

Also, you cannot use drupal_set_message in a function called by your batch operation function:

Type php
Date Thursday, November 20, 2008 - 12:39
User submin
Location http://localhost/scf/batch?id=33&op=do
Referrer http://localhost/scf/batch?op=start&id=33
Message Cannot modify header information - headers already sent by (output started at /RCS/agaric/agaric-sites/scf/sites/default/modules/taxonomy_xml/obo_format.inc:107) in /RCS/agaric/agaric-sites/scf/includes/common.inc on line 141.
Severity error
Hostname ::1

It appears to cause unhappiness!

Resolution

Even if your batch processing function is defined in the same file as the function calling batch, it is not necessarily in scope; if the file is conditionally included (not in the usual bootstrap process) it must added with the file attribute in the array providing the batch definition.

Searched words: 
Batch function silently fails batch processed but operations function never called Drupal batch operation not running

Comments

Thank you!

Thank you for pointing this out! Because you pointed this out, I only wasted 1 hour instead of 12. :-)

Bit me too

Yep, this one bit me too. Are you aware of any patches that aim to fix this? (I.e. throw a proper error.)

Thanks a million!

I was about to scream when I found this page. Thanks! Looks like it's still not fixed for Drupal 7 HEAD, I'll create an issue.

I love you!

Ben,

I couldn't figure out why by batch function wasn't being called even though it was in the same file as my batch_set. Well, that file was already an inc file.

THANK YOU!

~Michelle

Post new comment

The content of this field is kept private and will not be shown publicly.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • You can use Markdown syntax to format and style the text. Also see Markdown Extra for tables, footnotes, and more.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <blockquote> <small> <h2> <h3> <h4> <h5> <h6> <sub> <sup> <p> <br> <strike> <table> <tr> <td> <thead> <th> <tbody> <tt> <output>
  • Lines and paragraphs break automatically.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.