We have a website that updates numerous nodes nightly with an uploaded XML file. This XML file is then processed with Drupal's batch api, and when the XML file is uploaded manually, the script works perfectly. However, in real life, this XML file is uploaded programmatically by a script running on another server. Programmatically, the file gets uploaded and the batch begins properly, but on the successive redirects, the batch fails. This is because, the pseudo browser window from our publishing script closes.
Drush to the rescue
Luckily we have Drush installed on the server. After doing some digging we found that the commanddrush batch-process {bid}
will run the batch of whatever batch id you tell it. Perfect, now we can use a cron job on the server to process our batch after the XML file is published to the server.
Drush as a shell script
Before invoking Drush from cron, we need to created an executable Drush script that we can have cron run. Our script looks like this:
#!/usr/bin/env drush
// Find the newest batch job to run.
$x = db_fetch_object(db_query("SELECT bid FROM {batch} ORDER BY bid DESC LIMIT 1"));
if ($x->bid) {
// Some output for us to make sure the script is running.
drush_print('The batch ID is: ' . $x->bid);
$i = 1;
/*
Why a do while loop? Because we want the script to run continuously being sure to process the entire batch. we added a database query at the end to check for the ID we are processing periodically. We found that calling drush_invoke_process just once resulted in stopping before all results were processed.
*/
do {
// Call drush_invoke_process to mimic drush batch-process
drush_invoke_process("@self", 'batch-process', array($x->bid));
// Some more output for us humans.
drush_print('Running process #' . $i);
// Only query the database every 10 tries.
if($i % 10 == 0) {
drush_print('Check the database for the batch ID.');
// Query the database and see if the batch ID still exists.
$x = db_fetch_object(db_query("SELECT bid FROM {batch} WHERE bid = %d", $x->bid));
}
$i++;
} while ($x->bid);
}
else {
drush_print('No batch ID was found');
}
UPDATE: I had initially set this script to run under a cron job and it was not running correctly. After setting my crontab MAILTO: parameter, I quickly found out why. I was receiving the following error message:
PHP Fatal error: Call to undefined function db_fetch_object() in /usr/share/drush/commands/core/core.drush.inc(666) : eval()'d code on line 2
Drush command terminated abnormally due to an unrecoverable error. [error]
Error: Call to undefined function db_fetch_object() in
/usr/share/drush/commands/core/core.drush.inc(666) : eval()'d code,
line 2
As it turns out, my script was trying to run, but it didn't know what site I was referring to. Drush wasn't bootstrapping the site, and I was missing most of Drupal's API functions. The solution: Drush Site Aliases.