Skip to content

hook_civicrm_QueueRun

Summary

Fire hook_civicrm_queueRun_{$runner}.

Description

This event only fires if these conditions are met:

  1. The $queue has been persisted in civicrm_queue.
  2. The $queue has a runner property.
  3. The $queue has some pending tasks.
  4. The system has a queue-running agent.

Queue-items executed in this hook can have any (serializable) data-type, and you can receive multiple queue-items in a single batch.

If your queue-items are based on CRM_Queue_Task, then you do not need to implement this hook. You can rely on the standard implementation of hook_civicrm_queueRun_task.

Definition

hook_civicrm_queueRun_RUNNER(CRM_Queue_Queue $queue, array $items, &$outcomes)

Parameters

  • CRM_Queue_Queue $queue

    Queue which had the item(s).

  • array $items

    List of claimed items which we may evaluate.

    The number of items may vary based on the configuration and data. If the Queue has batch_limit=1 (default), then you will only receive one item. But if batch_limit is higher, then you may receive multiple items.

  • array &$outcomes

    The outcomes of each task. Each outcome should be 'ok', 'retry', or 'fail'.

    Keys should match the keys in $items.

Availability

  • hook_civicrm_queueRun_{$runner}: CiviCRM v5.51+
  • CRM_Queue_BasicHandlerTrait: CiviCRM v6.1+

Example

Create a queue and set the runner property, e.g.

$queue = Civi::queue('my-queue', [
  'type' => 'Sql',
  'runner' => 'my_stuff',
  'batch_limit' => 1,
  ...
]);
$queue->createItem(/* serializable data #1*/);
$queue->createItem(/* serializable data #2*/);
$queue->createItem(/* serializable data #3*/);

Whenever items are detected in my-queue, the background agent will fire hook_civicrm_queueRun_my_stuff.

To listen to this hook, use the helper BasicHandlerTrait:

/**
 * @service civi.queue.my_stuff
 */
class MyHandler extends AutoService implements EventSubscriberInterface {

  use CRM_Queue_BasicHandlerTrait;

  public static function getSubscribedEvents() {
    return ['&hook_civicrm_queueRun_my_stuff' => 'runBatch'];
  }

  protected function runItem($item, \CRM_Queue_Queue $queue): void {
    print_r(["Received item:" => $item));a

    // If this function ends normally, then we consider the $item successful.

    // If this function encounters a recoverable error, then we check the $queue configuration
    // to decide what to do next (e.g. retry, abort, delete, etc).

    // If this function abends (PHP fatal, power-outage, etc), then any pending items in the
    // batch (incl $item and its successors) will be retried later.
  }

  // Optionally, pre-validate items before executing them.
  // protected function validateItem($item): bool {}

  // Optionally, make a loggable summary of the
  // protected function getItemDetails($item): array  {}
}

Note that the hook calls our pre-existing/inherited method (runBatch()). We must implement runItem() for the main logic, and we can (optionally) implement methods like validateItem().

Of course, you don't need to use BasicHandlerTrait. You can implement the hook directly, as in this minimal example:

function myextension_civicrm_queueRun_my_stuff(CRM_Queue_Queue $queue, array $items, array &$outcomes): void {
  foreach ($items as $key => $item) {
    $outcomes[$key] = /* do something with $item and get outcome */;
  }
}

This looks simpler at first, but it omits a lot of details about batched error handling. You need to identify errors, map them back to specific tasks, decide how to report the error, and decide what to do with other/remaining tasks. This may be necessary and worthy in some cases -- for example, if your logic really runs faster as a batched operation, or if you integrate with some external API that has its own error protocols. But in general, the BasicHandlerTrait::runItem() is easier to implement.