Pasar al contenido principal

Crear colas con Queue API (Drupal 7)

Las colas se suelen utilizar en casos para ejecutar tareas que tienen que ser ejecutadas en segundo plano dado el tiempo de ejecución que conlleva. Como posibles casos de uso tenemos: generación de contenido/entidades a partir de llamadas de un servicio, generación de contenido masivo tras las acciones de un usuario, cálculo exhaustivo de datos, etcétera.

Por ejemplo, el módulo Remote Entity API, que permite cargar entidades a partir de contenido de otros sitios, guarda cada contenido en una entidad dentro de Drupal. El módulo permite configurar esta entidad para que cada registro se borre tras un determinado tiempo. Pues bien, esto se hace mediante colas.

Como ejemplo básico vamos a crear una función que recibirá como argumentos una lista de identificadores de usuario y una fecha en formato Y-m-d.

Está función encolará estos usuarios para borrar los nodos de cada uno, creados en el intervalo de un día, lo cual podría dar problemas si se hace en el mismo momento.

Declaración

Primero declararemos la cola usando el hook_cron_queue_info:

/**
 * Implements hook_cron_queue_info().
 */
function test_cron_queue_info() {
  $queues['test_queue_user_nodes_delete'] = array(
    'worker callback' => 'test_queue_user_nodes_delete_queue_callback',
    'time' => 60
  );
  return $queues;
}

Aquí podemos ver las siguientes cosas:

  • El nombre de la cola es test_queue_user_nodes_delete, esto es el nombre de la cola y se utilizará para encolar los elementos.
  • Con el worker callback estamos indicando la función que procesará cada elemento de la cola.
  • Con time podemos indicar el tiempo máximo que puede estar procesandose la cola. Esto se hace para evitar la sobrecarga de los elementos procesados. Los demás elementos se procesarán en los siguientes procesados de elementos.

Existe una opción más, skip on cron, que indica que no queremos que se procese la cola en el cron (donde normalmente se ejecuta). De está forma puedes llamar a la cola en el momento que necesites. Esto lo veremos más adelante.

Aquí estaría la función encargada de borrar los usuarios del nodo de ese día:


function test_queue_user_nodes_delete_queue_callback($item) {
  $query = new EntityFieldQuery();
  $date = strtotime($item['date'] . ' 00:00:00');
  $date_day_left = strtotime($item['date'] . ' 00:00:00 +1 day');
  $query->entityCondition('entity_type', 'node');
  $query->propertyCondition('uid', $item['uid']);
  $query->propertyCondition('created', array($date, $date_day_left), 'BETWEEN');
  $result = $query->execute();
  if (!empty($result['node'])) {
    // Extract ids of nodes.
    $nodes = array_keys($result['node']);
    node_delete_multiple($nodes);
  }
}

Aquí vemos que la función recibe como parámetro $item , esto son los datos que hemos mandado a encolar.

Encolamiento

Ahora que tenemos el mecanismo para procesar los elementos de cola necesitamos, por supuesto, encolar los elementos. Para ello debemos de crear una función que instancie la cola y vaya añadiendo los elementos.

Esta es la función que hace el trabajo:


function test_queue_test_queue_user_nodes_delete_enqueue($uids, $date) {
  $queue = DrupalQueue::get('test_queue_user_nodes_delete');
  foreach ($uids as $uid) {
    $item = array(
      'uid' => $uid,
      'date' => $date,
    );
    $queue->createItem($item);
  }
}

Aquí hacemos lo siguiente:

  • Instanciamos nuestra cola con DrupalQueue::get
  • Añadimos los items a la cola con el método createItem

De esta forma ya tenemos una cola que procesará los items como necesitemos, y una forma de añadir los elementos a la cola.

 

Ejecución

Para poder ejecutar la cola y que empiece a procesar elementos podemos usar el cron, que es la forma que se usará por defecto. Si quisieramos que las colas se procesasen cada menos tiempo solo tendríamos que reducir el tiempo del cron.

Otra forma de ejecutar las colas es mediante drush, con el commando queue-run.

Ejemplo: 

drush queue-run test_queue_user_nodes_delete

También es posible ejecutar las colas desde Drupal, instanciando la cola y procesando cada elemento.

Ejemplo:

$queue = DrupalQueue::get('test_queue_user_nodes_delete');
$item = $queue->claimItem();
test_queue_user_nodes_delete_queue_callback($item->data);
$queue->deleteItem($item);

Aquí lo que hacemos es instanciar la cola, extraer el primer elemento (con el método claimItem), y procesarlo. Tras eso lo borramos mediante el método deleteItem.

Omar Lopesino

Omar Lopesino

Senior Drupal developer