Ho bisogno di un'attività cron per l'elaborazione di una coda?


32

Ho un compito che richiede circa 45 minuti per essere completato e deve avvenire ogni giorno (sincronizzazione degli utenti con diversi database esterni, ecc.).

Per gestire il lavoro, ho impostato una coda cron con hook_cron_queue_info()il seguente:

function mymodule_cron_queue_info() {
  $queues = array();
  $queues['update_users_queue'] = array(
    'worker callback' => '_mymodule_process_user_queue_item',
    'time' => 120,
  );
  return $queues;
}

Riempo la coda usando questa funzione:

function mymodule_queue_all_users_for_synching() {
  //...query for users...

  $queue = DrupalQueue::get('update_users_queue');
  foreach($users as $user) {
    $queue->createItem($user);
  }
}

La funzione di riempimento della coda viene chiamata come attività cron. Uso Elysia Cron , quindi la mia implementazione di hook_cronapi()è:

function mymodule_cronapi($op, $job = NULL) {
  $items = array();
  $items['queue_users_for_synch'] = array(
    'description' => 'Queue all user accounts for synching.',
    'rule' => '0 3 * * *', // Run this job every day at 3am.
    'callback' => 'mymodule_queue_all_users_for_synching',
  );
  return $items;
}

La funzione worker per ciascun elemento della coda, definita in mymodule_cron_queue_infoè simile a:

function _mymodule_process_user_queue_item($item) {
  //...synchronize user ($item)...
}

La mia domanda è: quando cron inizierà effettivamente a elaborare la coda?

Supponiamo che riempia la coda ogni giorno alle 3 del mattino e che voglia elaborarla 120 secondi ogni 30 minuti fino a quando non viene eseguita : devo creare un'altra attività cron?


Vorrei menzionare che sto usando Drupal 7.
joe_flash

1
Sono curioso anche di queste domande. Mi piacerebbe sentire sì o no. Usiamo pesantemente l'API di coda in uno dei nostri progetti D7. Visivamente ho visto che le righe della tabella {queue} vengono cancellate quando il cron viene eseguito. Quindi supponiamo che sia sì.
Sivaji,

Risposte:


19

Quando Drupal esegue attività cron, gestisce automaticamente qualsiasi coda cron definita dai moduli, in drupal_cron_run(); hook_cron()vengono invocate le prime implementazioni, quindi vengono svuotate le code cron.

Grazie all'implementazione hook_cronapi(), puoi aggiungere una voce per un'altra funzione che gestisce la coda cron del tuo modulo.

function mymodule_cronapi($op, $job = NULL) {
  $items = array();

  $items['queue_users_for_synch'] = array(
    'description' => 'Queue all user accounts for synching.',
    'rule' => '0 3 * * *', // Run this job every day at 3am.
    'callback' => 'mymodule_queue_all_users_for_synching',
  );

  $items['clean_queue'] = array(
    'description' => 'Clean the queue for the user synching.',
    'rule' => '0 4 * * *', // Run this job every day at 4 AM.
    'callback' => 'mymodule_clean_queue',
  );

  return $items;
}

function mymodule_clean_queue() {
  $queues = module_invoke('mymodule', 'cron_queue_info');
  drupal_alter('cron_queue_info', $queues);

  // Make sure every queue exists. There is no harm in trying to recreate an
  // existing queue.
  foreach ($queues as $queue_name => $info) {
    DrupalQueue::get($queue_name)->createQueue();
  }

  foreach ($queues as $queue_name => $info) {
    $function = $info['worker callback'];
    $end = time() + (isset($info['time']) ? $info['time'] : 15);
    $queue = DrupalQueue::get($queue_name);
    while (time() < $end && ($item = $queue->claimItem())) {
      $function($item->data);
      $queue->deleteItem($item);
    }
  }
}

L'alternativa è consentire a Drupal di gestire la coda cron per te, ma ciò accade quando vengono eseguite attività cron di Drupal. Se si desidera svuotare la coda cron del modulo più frequentemente, è possibile solo aggiungere una nuova attività cron gestita dal modulo Elysia Cron.

Il modulo Elysia Cron gestisce le code cron elysia_cron_run(); questa funzione viene invocata da elysia_cron_cron()(un'implementazione di hook_cron()), drush_elysia_cron_run_wrapper()(un callback del comando Drush) e dal suo stesso cron.php . Se hai seguito le istruzioni nel file INSTALL.txt (in particolare in "PASSAGGIO B: MODIFICA CRONTAB DI SISTEMA (OPZIONALE)") e hai sostituito qualsiasi invocazione di http://example.com/cron.php con http: // esempio .com / sites / all / modules / elysia_cron / cron.php , il modulo Elysia Cron dovrebbe già gestire le code cron. Il codice che ho suggerito potrebbe essere usato per velocizzare la gestione delle code cron utilizzate dal tuo modulo, se ce n'è effettivamente bisogno.

// This code is part of the code executed from modules/elysia_cron/cron.php.
define('DRUPAL_ROOT', getcwd());

include_once DRUPAL_ROOT . '/includes/bootstrap.inc';
drupal_override_server_variables(array(
  'SCRIPT_NAME' => '/cron.php',
));
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

if (!isset($_GET['cron_key']) || variable_get('cron_key', 'drupal') != $_GET['cron_key']) {
  watchdog('cron', 'Cron could not run because an invalid key was used.', array(), WATCHDOG_NOTICE);
  drupal_access_denied();
}
elseif (variable_get('maintenance_mode', 0)) {
  watchdog('cron', 'Cron could not run because the site is in maintenance mode.', array(), WATCHDOG_NOTICE);
  drupal_access_denied();
}
else {
  if (function_exists('elysia_cron_run')) {
    elysia_cron_run();
  }
  else {
    drupal_cron_run();
  }
}

Ah, grazie @kiam! Questo è quello che sospettavo, ma non riuscivo a avvolgerci il cervello.
joe_flash,

In realtà, penso che mi manchi qualcosa qui. Hai detto che l'alternativa è lasciare che Drupal gestisca la coda cron per me; Immagino che parte della mia domanda originale sia quando ciò accade realmente ? Ogni volta che crontab richiede cron.php? In tal caso, ciò accade ogni minuto (vedi il mio primo commento sulla risposta di @ David).
joe_flash,

1
Vale la pena ricordare che sembra che Elysia cron abbia la sua implementazione del processore cron_queue elysia_cron_runcon code cron che vengono elaborate automaticamente ogni volta che viene richiesto il cron.php di Elysia.
David Thomas,

@joe_flash Mi dispiace: avrei dovuto essere più chiaro. Sì, Drupal esegue le attività cron quando viene richiamato cron.php (per ogni versione di Drupal fino a Drupal 7). In Drupal 8, cron.php non è più presente e le attività cron vengono eseguite utilizzando un percorso di sistema diverso.
kiamlaluno

2

La coda verrà popolata tramite il gancio cronapi Elysia all'ora impostata.

Tuttavia, la coda verrà elaborata ogni volta che si verifica l'esecuzione cron standard di Drupal.

Vedi questo snippet di elaborazione di callback del lavoratore alla fine del core: drupal_cron_run

 foreach ($queues as $queue_name => $info) {
    $function = $info['worker callback'];
    $end = time() + (isset($info['time']) ? $info['time'] : 15);
    $queue = DrupalQueue::get($queue_name);
    while (time() < $end && ($item = $queue->claimItem())) {
      $function($item->data);
      $queue->deleteItem($item);
    }
  }

David, forse Elysia introduce un po 'di complicazioni qui? Ho impostato crontab per attivare lo cron.phpscript Elysia ogni minuto , il che consente a Elysia di controllare i tempi delle attività con una risoluzione minima. Nessuna attività viene effettivamente eseguita ogni minuto, che è ciò che mi ha fatto pensare che avevo bisogno di creare un'attività per lavorare specificamente sulle code?
joe_flash,

@joe_flash fintanto che drupal_cron_runviene chiamato, il callback del gestore code cron verrà elaborato.
David Thomas,

Ah, penso che tu abbia ragione. Tuttavia, drupal_cron_runnon viene chiamato dallo cron.phpscript Elysia (quando Elysia è abilitato); elysia_cron_runviene invece utilizzato.
joe_flash,

In tal caso, sembra che non sia possibile utilizzarlo hook_cron_queue_infocon Elysia cron, a meno che non si specifichi il callback del proprio lavoratore, come da drupal_cron_runframmento di funzione principale sopra.
David Thomas,

elysia_cron_runnon chiama drupal_cron_run, ma fa chiamata module_invoke_all('cron_queue_info')e fa alcuni di fantasia-pantaloni gestione che fa fumo venire fuori le mie orecchie multi-canale.
joe_flash,

1

come indicato sopra quando si utilizza Elysia Cron le code non vengono elaborate.

tu (e drupal) non avete accesso a code che altrimenti verrebbero eseguite su drupal_run_cron

la soluzione alternativa è creare un'attività cron personalizzata (questo sarà visibile a elysia cron) per elaborare tutte le code o quella desiderata e invocare l'elaborazione della coda lì. vale a dire:

function mymodule_cron() {
// below is copied from drupal_cron_run() in common.inc

// Grab the defined cron queues.
$queues = module_invoke_all('cron_queue_info');
drupal_alter('cron_queue_info', $queues);

//if you want to target only one queue you can remove 'foreach'
and your $info = $queues['your_queue'];

  foreach ($queues as $queue_name => $info) {
    if (!empty($info['skip on cron'])) {
      // Do not run if queue wants to skip.
      continue;
    }
    $callback = $info['worker callback'];
    $end = time() + (isset($info['time']) ? $info['time'] : 15);
    $queue = DrupalQueue::get($queue_name);
     while (time() < $end && ($item = $queue->claimItem())) {
      try {
        call_user_func($callback, $item->data);
        $queue->deleteItem($item);
      }
      catch (Exception $e) {
        // In case of exception log it and leave the item in the queue
        // to be processed again later.
        watchdog_exception('cron', $e);
      }
    }
  }
}

ora l'elaborazione delle code può essere controllata da ElysiaCron


0

Non uso Elysia, ma la mia soluzione è sempre stata una cosa del genere:

function mymodule_cron() {
  $queue = DrupalQueue::get('mymoudule_queue');
  $queue->createQueue();
  $item = $queue->claimItem(300);

  if (!empty($item->data)) {

    // Do the work.

    if ($sucess) {
      $queue->deleteItem($item);
      watchdog('mymodule', 'It worked.');
    }
    else {
      watchdog('mymodule', 'It did not work!', array(), WATCHDOG_ALERT);
    }
  }
}

Gestisce solo un elemento, per ogni esecuzione cron. Forse vuoi cambiarlo.


0

Ho anche cercato di avvolgere la mia testa, poiché sto usando l'API Queue per la prima volta insieme a Elysia cron. Ad un esame più attento si può vedere che Elysia cron esegue gli oggetti in coda quando viene chiamata la funzione elysia_cron_run . Vedi questo frammento dalla riga 1044 nel file elysia_cron.module :

if (EC_DRUPAL_VERSION >= 7) {
  // D7 Queue processing
  foreach ($queues as $queue_name => $info) {
    $function = $info['worker callback'];
    $end = time() + (isset($info['time']) ? $info['time'] : 15);
    $queue = DrupalQueue::get($queue_name);
    while (time() < $end && ($item = $queue->claimItem())) {
      $function($item->data);
      $queue->deleteItem($item);
    }
  }
}

Questo mi ha aiutato a demistificare l'elaborazione della coda quando utilizzo Elysia cron.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.