4

I am working on Drupal 8 and batch API. I created the batch api calling importingmatch and it should automatically importing every 1 hour.

My solution is use Drush for make it works without the browser, but I don't know how I can get the batch id.

Here is my code about the Batch API:

// Set up the Batch API
    $batch = array(
        'operations' => $operations,
        'finished' => 'importingmatch_finishedBatch',
        'title' => t('Import match'),
        'init_message' => t('Starting import match.....'),
        'progress_message' => t('Completed @current step of @total.'),
        'error_message' => t('Import match deletion has encountered an error.'),
    );

    batch_set($batch);

Currently, this batch is runing perfect if I access from my PC. Url: www.mysite.com/importing_match I am not sure how make it working from the server Centos with Drush, I need the batch ID for execute: Drush batch-process

UPDATE: - Interesting with the Command for Drush, I created custom Command from my module. Following from here: https://www.chapterthree.com/blog/how-to-create-custom-drush-commands. But it's still not working, it's showing:

The drush command '<name>' could not be found.

I changed from localhost to 127.0.0.1 from the settings.php but it's not helpful. Any idea?

2
  • Which batch ID are your referring to ?
    – pbonnefoi
    Commented Jan 11, 2017 at 17:33
  • Create your own drush command to initiate your batch process inside drush.inc of your module. Commented Jan 11, 2017 at 19:17

3 Answers 3

9

Instead of using Cron API you could provide your own custom Drush command and implement Batch API there. And then execute this Drush command using your server's crontab.

Following comes a sample command that implements a batch. Inside module_name.drush.inc put:

function module_name_drush_command() {
  $items = array();
  $items['migrate-batch-list'] = array(
    'description' => 'Migrate import match',
    'examples' => array(
      'drush migrate-batch-list' => 'Migrate import match',
    ),
  );
return $items;
}

function drush_module_name_migrate_batch_list() {
  drush_print('Migrate import match list.');

  $operations = array(...something here you want.);
  $batch = array(
    'operations' => $operations,
    'finished' => 'importingmatch_finishedBatch',
    'title' => t('Import match'),
    'init_message' => t('Starting import match.....'),
    'progress_message' => t('Completed @current step of @total.'),
    'error_message' => t('Import match deletion has encountered an error.'),
  );

  // Initialize the batch.
  batch_set($batch);

  // Start the batch process.
  drush_backend_batch_process();
}

Note: You can run this from terminal as drush migrate-batch-list

0
13

You don't. Batch API is to do long-running processing with user-interaction.

For cron, you either use Queue API or you just process for N seconds/things in your hook_cron() implementation, and in both cases, cron will be calling you repeatedly until it is eventually done.

If you want to process as fast as possible then either use a different queue processing that doesn't run on cron or make a custom script/drush command that you execute separate from cron, so that you don't block other cron jobs.

1
2

Sometimes it's just simply not possible to avoid batch process in cron jobs (user_cancel using batch...). My case was to delete users periodically if they were inactive for a certain time. Here is how I solved it, it can give a good idea of how you can use it, I've stripped out the totally irrelevant parts leaving some guides for easier adaption.

function MODULE_cron() {
  [...]
  $to_delete_users = User::loadMultiple(/* User ids to be deleted */);

  $edit = [
    'user_cancel_notify' => FALSE,
  ];
  $failed_deletion_ids = [];
  foreach ($to_delete_users as $user) {
    [...]

    try {
      // Mark user for cancel.
      user_cancel($edit, $user->id(), 'user_cancel_reassign');

      // Drush check is failing, due wrong condition, however this may not
      // correct either, isset($batch['sets']) could be better.
      $batch =& batch_get();
      if (count($batch) > 0) {
        // Process the deletion with batch.
        // This is not ideal, but in this way we won't notify users that
        // wasn't deleted at the end also it doesn't break the whole process,
        // max the current loop will fail.
        if (function_exists('drush_backend_batch_process')) {
          // For drush.
          drush_backend_batch_process();
        }
        else {
          // For the rest.
          $batch['progressive'] = FALSE;
          batch_process();
        }
      }

      $mail_manager->mail(/* Parameters for mail sending */);
    }
    catch (Exception $e) {
      $failed_deletion_ids[] = $user->id();
      \Drupal::logger('cron')->error('Failed to cancel %uid user account. Please check the error message: %message in %file file at line %line and the backtrace: %backtrace NOTE: this error may not the original one!', [
        '%uid' => $user->id(),
        '%message' => $e->getMessage(),
        '%file' => $e->getFile(),
        '%line' => $e->getLine(),
        '%backtrace' => $e->getTraceAsString(),
      ]);
    }
    finally {
      // Reset batch.
      $batch = [];
    }
  }
  /* Some other stuff and make a report */
  [...]
}

There are two important things to note here.
First, if you using the drush function like it was suggested in the other answer, Behat can fail (if you have or the UI cron execution), because in that case drush is not loaded. That's why I've checked if it exists or not.
Second, if you want to run another batch process after a finished one, first you need to reset back to default the batch variable, or it will hang on the second run/call/loop.
This solution should also work when you call cron from the UI.

1
  • When using this code inside a class, $batch =& batch_get(); should be replaced with $batch = &$this->batchGet(); and the metod is like protected function &batchGet() {return batch_get();}.
    – dxvargas
    Commented Jul 28, 2023 at 15:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.