I have used hook_cron() function. In hook_cron() function i implemented batch process and drupal_set_message(). While running cron, batch process not working but drupal_set_message() prints the message.

How to execute Batch Process based on cron run?

Comments

jaypan’s picture

I believe the batch API requires browser access to work - and there is no browser involved in the cron process. You can look at the Queue API that will work in hook_cron().

Contact me to contract me for D7 -> D10/11 migrations.

savithac’s picture

I have used hook_cron_queue_info(). I have written code for batch process inside hook_cron_queue_info(). This function works but only batch process not run.

N1ghteyes’s picture

Could you paste your cron queue function in here? As Jaypan says, batch API wont itself work in cron, you will need to use hook_cron_queue_info and write your own code to batch the process without using the batch API.

jaypan’s picture

You can embed your batch process in a function, and you can even embed it in another function, which you could even embed in another function. But if the originally triggering function is cron, then your batch process will not work no matter how many functions you embed it into.

The batch process requires a browser to work. If you are not using a browser to access the batch process, it will not work.

Contact me to contract me for D7 -> D10/11 migrations.

veso_83’s picture

The batch api is primary design to work with forms and it depends what is the purpose of your use, but you can create a function that mimic form submission, and then you can use batch together with cron, assume you have function that will be triggered by a rule on cron run, so this function is function1:

<?php
function function1 () {
    $form_state = array();
    $form_state['values']['hidden_value'] = 1;
    $form_state['values']['op'] = 'Test';
    $form_state['values']['submit'] = 'Test';
    drupal_form_submit('function1_batch_form',    
    $form_state);
} 

function function1_batch_form($form, &$form_state) {
  $form['hidden_value'] = array(
    '#type' => 'hidden',
    '#value' => 1,
  );
  return $form;
}

function function1_batch_form_submit($form, &$form_state) {
  if ($form_state['values']['hidden_value'] == 1) {
    $batch = function1_batch_process($date);
    batch_set($batch);
  }
}
?>

From this point it will be normal batch process

drupalshrek’s picture

Thanks veso_83, your method does work. So, it is possible to indirectly call batch from cron. Great.

Below is my actual code (used as part of nodes (=words) to a particular taxonomy (=lesson), e.g. http://lingopolo.com/french/online-lessons/examples-of-cow-in-use/words):

/**
 * Add the given nodes to the given lesson.
 * 
 * @param $nids
 *   An array of node ids. 
 * @param $tid
 *   The taxonomy id of the lesson to which the nodes should be added.
 */
function phrases_add_nodes_to_lesson($nids, $tid) {
  $form_state = array();
  $form_state['values']['op'] = 'Test';
  $form_state['values']['submit'] = 'Test';
  $form_state['values']['nids'] = $nids;
  $form_state['values']['tid'] = $tid;
  
  drupal_form_submit('phrases_batch_form', $form_state);
}

/**
 * Form for adding nodes to a taxonomy lesson.
 * 
 * This form is required because hook_cron() cannot directly call a batch job
 * but it can call a drupal_form_submit() and a form can run a batch!
 */
function phrases_batch_form($form, &$form_state) {
  $form['nids'] = array(
      '#type' => 'hidden',
      '#value' => $form_state['values']['nids'],
  );
  $form['tid'] = array(
      '#type' => 'hidden',
      '#value' => $form_state['values']['tid'],
  );
    
  return $form;
}

/**
 * Handle the submission of the form to add nodes to a lesson. 
 */
function phrases_batch_form_submit($form, &$form_state) {
  $nids = $form_state['values']['nids'];
  $tid = $form_state['values']['tid'];
  
  // Add the target tid to each of the nodes
  foreach ($nids as $nid) {
    $operations[] = array('phrases_add_node_to_lesson', array($nid, $tid));
  }
  
  $batch = array(
    'title' => 'Adding examples lesson',
    'operations' => $operations,
    'finished' => 'phrases_creation_finished',
  );
  	
  batch_set($batch);
}

drupalshrek

rajveergangwar’s picture

I love this solution.

Rajveer Singh
rajveer.gang@gmail.com

j.b’s picture

Make a drush command for your batch and then execute the command on a cron tab.
On D7 you could also use the background process module

ranieri machado’s picture

/**
 * Function called by cron.
 */
function function1() {
  $values = ['confirm' => 1];
  $form_state = (new FormState())->setValues($values);
  \Drupal::formBuilder()->submitForm('Drupal\my_module\Form\ConfirmImportForm', $form_state);
}
 

ConfirmImportForm.php:

<?php

namespace Drupal\my_module\Form;

use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;

/**
 * Defines a confirmation form to confirm importing manually.
 */
class ConfirmImportForm extends ConfirmFormBase {

...

  public function submitForm(array &$form, FormStateInterface $form_state) {
    $batch = function_that_builds_the_batch_array();
    batch_set($batch);
    $url = new Url('route_to_some_page');
    return $form_state->setRedirectUrl($url);
  }

 ....

}
 

bwaindwain’s picture

Thanks @ranieri-machado.

When cron is triggered via drush, batch_process() throws an error about "Route required in Drupal\Core\Url::fromRouteMatch()". Set a route in the submitForm() manually with:

if (PHP_SAPI === 'cli') {
  $route = new Route('/');
  $route_match = new RouteMatch('<front>', $route);
  \Drupal::getContainer()->set('current_route_match', $route_match);
}
bhanojeerao’s picture

Hello Ranieri Machado,

Wonderful solution for batch process with in cron. Worked fine. Thanks. 

Bhanojee Rao