0

I'm trying to print ~100 nodes worth of content (Performance Plans) out to the private file system using the batch API. My process works perfectly up until about 10 of them and then times out. The timeout page happens before it even gets to the batch page with the progress bar. It appears to me like it might be running all 100 as a single batch vs breaking them up. I'm not sure exactly what I'm missing... Any help would be greatly appreciate.

BulkPrintForm.php

<?php
 namespace Drupal\bulk_print_to_files\Form;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\node\Entity\Node;
 use Drupal\Core\Url;
/**
 * Class BulkAddForm.
 *
 * @package Drupal\create_perf_plan_for_new_year\Form
 */
class BulkPrintForm extends FormBase {
  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'bulk_print_form';
  }
  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['bulk_add'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Print Performance Plans'),
    );
    return $form;
  }
  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $nids = \Drupal::entityQuery('node')
      ->condition('type','perf_plan')
      ->condition('field_performance_plan_year', 18)
      ->range(0, 100)
      ->sort('created' , 'DESC')
      //->condition('nid', 6273)
      ->execute();
    //$year = "1920"; //$year being left here as an example of passing a variable to the bulk process. Not currently in use.

    $operations = [];

    foreach ($nids as $nid) {
      $operations[] = [
        [
          $this->batchFunction($nid),
          [$nid]
        ],
      ];
    }

    $batch = array(
      'title' => t('Bulk Print happening within the Bulk Print Form file...'),
      'operations' => $operations,
      'progress_message' => t('Processed @current out of @total. Estimated time: @estimate.'),
      'init_message'=> t('Performance Plans are being printed to the private directory!'),
      'finished' => '\Drupal\bulk_print_to_files\BulkPrintNode::bulkPrintFinishedCallback',
      'error_message' => t('The migration process has encountered an error. (Make sure the folder you are placing these in exists!)'),
    );
    batch_set($batch);
  }
  function batchFunction($nid) {
    $print_engine = \Drupal::service('plugin.manager.entity_print.print_engine')->createSelectedInstance('pdf');
    $print_builder = \Drupal::service('entity_print.print_builder');
    $path = 'private';
    $filename = "perfplans/{$nid}.pdf";
    $nodes = \Drupal::entityTypeManager()->getStorage('node')->load($nid);
    $uri = $print_builder->savePrintable([$nodes], $print_engine, $path, $filename);
  }
}

BulkPrintNode.php

<?php
namespace Drupal\bulk_print_to_files;
use Drupal\node\Entity\Node;
use Drupal\Core\Url;

function bulkPrintFinishedCallback($success, $operations) {
    if ($success) {
      $message = 'Performance plan printed.';
      $type = 'status';
    }
    else {
      $message = t('Encountered an error during bulk performance plan creation.');
      $type = 'error';
    }
    drupal_set_message($message, $type);
  }
}

Is there a way to limit these to say doing 5 at a time and then moving on to another set? Im under the impression I just have the batching process setup incorrectly.

1
  • Your code seems to be fine as it is calling 1 node at a time in batch. There must be some issue with a particular node. So can you check if you get any error in drupal watch dog entry? Or if you can point out which node it is, try to run that node only and see if you still have timeout.
    – Bharat
    Commented Jun 19, 2018 at 3:11

1 Answer 1

1

In BulkPrintForm::submitForm() you invoke batchFunction method by calling it directly via $this->batchFunction($nid) line. This will effectively skip the batch API and run it for all nodes. You should pass the callback instead, check http://cgit.drupalcode.org/examples/tree/batch_example/src/Form/BatchExampleForm.php#n93

2
  • Thanks this makes sense. How would I pass a parameter to something like 'batch_example_op_1', ? I need to pass the $nid into the function on each pass of the operation? Commented Jun 19, 2018 at 17:36
  • Look at comments to linked example, especially: // Each operation is an array consisting of // - The function to call. // - An array of arguments to that function.
    – zaporylie
    Commented Jun 19, 2018 at 20:31

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.