Update hook batch stops halfway through I rarely ask questions on SE but now the teacher has become the student because this is driving me mad. I am doing a simple batch through an update hook and publishing some unpublished nodes. I am aware I could do this with a flat query, but I am preferring to use the batch system.

For whatever reason it arbitrarily stops at 50% no matter what I do. I have tried modifying the nodes per pass, etc. No errors. It just stop at the halfway point. When I debug the hook, I can see the counter variable increments right up to halfway and then stops. This is the hook. Am I crazy?

function mymodule_update_7200(&amp;$sandbox) {
// Initialize the batch
  if (!isset($sandbox['total'])) {
    $result = db_query('SELECT nid FROM {node} n WHERE n.type = :type AND n.status = 0', array(':type' =&gt; 'event'));
    $sandbox['total'] = $result-&gt;rowCount();
    $sandbox['current'] = 0;

    // Disable Scheduler
    module_disable(array('scheduler'));
    drupal_set_message(t('The scheduler module was disabled'));
  }

  $nodes_per_pass = 20;

  // Get the nodes to process during this pass.
  $result = db_query_range('SELECT nid FROM {node} n WHERE n.type = :type AND n.status = 0', $sandbox['current'], $nodes_per_pass, array(':type' =&gt; 'event'));
  foreach($result as $row){

    $node = node_load($row-&gt;nid);

    // Run a database update directly so we don't trigger any API calls through node_save
    db_query("UPDATE {node} n SET n.status = 1 WHERE n.nid = :nid", array(':nid' =&gt; $row-&gt;nid));

    // Log the event being published
    watchdog(
      'events',
      'Event was published: %title',
      array('%title' =&gt; $node-&gt;title),
      WATCHDOG_NOTICE,
      l('View', "node/$node-&gt;nid")
    );

    // Increment "current" by 1.
    $sandbox['current']++;
  }

  // Set the value for finished. If current == total then finished will be 1, signifying we are done.
  $sandbox['#finished'] = ($sandbox['current'] / $sandbox['total']);

  if ($sandbox['#finished'] === 1) {
    drupal_set_message(t('@nodes events were published. View the log for details.', array('@nodes' =&gt; $sandbox['total'])));
  }
}
The problem in this case is caused because results query differs between iterations.

You should replace:

$result = db_query_range('SELECT nid FROM {node} n WHERE n.type = :type AND n.status = 0', $sandbox['current'], $nodes_per_pass, array(':type' =&gt; 'event')); 

with 

$result = db_query_range('SELECT nid FROM {node} n WHERE n.type = :type AND n.status = 0 ORDER BY n.nid ASC', 0, $nodes_per_pass, array(':type' =&gt; 'event'));