4

I have a Plugin\QueueWorker that creates a queue of emails to send from nodes that are created/updated throughout the day. I've defined a processItem() method, as well as an arbitrary function (let's call it mymodule_add_to_queue()) that runs $queue->createItem() to add the node to the queue. When cron runs, all the items in the queue get run, which is fine and dandy.

The only problem is that cron is running every hour, and it seems the QueueWorker class will run the process every time, when I only want it to run once, say between 2am and 3am.

I have the code that checks the REQUEST_TIME and the state of the last time it ran and all that, however I don't know where to put it. Even if it goes into hook_cron(), it doesn't appear to make any difference to the default behaviour.

Pseudocode for what kind of thing I'd be expecting to happen is:

<?php

// @file src/Plugin/QueueWorker/MyModuleCronQueueWorkerEmailSend.php
class MyModuleCronQueueWorkerEmailSend extends QueueWorkerBase {
  public function __construct () {
    this.auto_cron = FALSE;
  }
  public function processItem() {
    doSomething();
  }
}

// @file mymodule.module
function mymodule_add_to_queue() {
  $queue = \Drupal::queue('mymodule_queue_worker_email_send');
  $queue->createItem(['foo' => 'bar']);
}

function mymodule_cron() {
  if (some_cron_conditionals()) {
    $queue = \Drupal::queue('mymodule_queue_worker_email_send');
    $queue->process();
  }
}

... this may be completely out of scope though, or there may be a really obvious other method I'm missing. Any thoughts? As always, thanks in advance :)

2

Copied from \Drupal\Core\Annotation\QueueWorker, the annotation and placd where the @QueueWorker annotation is documented.

 * Worker plugins are used by some queues for processing the individual items
 * in the queue. In that case, the ID of the worker plugin needs to match the
 * machine name of a queue, so that you can retrieve the queue back end by
 * calling \Drupal\Core\Queue\QueueFactory::get($plugin_id).
 *
 * \Drupal\Core\Cron::processQueues() processes queues that use workers; they
 * can also be processed outside of the cron process.
 *
 * Some queues do not use worker plugins: you can create queues, add items to
 * them, claim them, etc. without using a QueueWorker plugin. However, you will
 * need to take care of processing the items in the queue in that case. You can
 * look at \Drupal\Core\Cron::processQueues() for an example of how to process
 * a queue that uses workers, and adapt it to your queue.

See the last paragraph, the solution is simply to just fill an arbitrary queue and then implement similar logic as Cron::processQueues() for your queue to process the items when you want. Nothing will happen automatically with items of a queue that doesn't have a worker plugin.

Instead of a plugin, you can implement your login in a service instead and call that from your own cron implementation.

  • Thanks, that may be a good idea. Is there a simple example you know of of approaching it this way? I can't see anything internally that implements QueueInterface, but that seems like the right place to be looking. – Matt Fletcher Apr 19 '17 at 9:13
  • Oh just noticed it's probably about extending DatabaseQueue – Matt Fletcher Apr 19 '17 at 9:23
  • I've made an edit to your answer, hope that's okay. – Matt Fletcher Apr 19 '17 at 14:12
  • You should not have to implement anything like that. Just get a queue instance with \Drupal::queue('yourmodule_foobar'); and then use ->createItem() on that. And then in your cron hook, claimItem() and process them. – Berdir Apr 19 '17 at 15:47
0

Try using https://www.drupal.org/project/ultimate_cron, which should give you a fine-grained control over when each cron task runs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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