it-swarm.com.de

Benötige ich eine Cron-Aufgabe zum Verarbeiten einer Warteschlange?

Ich habe eine Aufgabe, die ungefähr 45 Minuten dauert und jeden Tag erledigt werden muss (Synchronisieren von Benutzern mit mehreren externen Datenbanken usw.).

Um die Arbeit zu erledigen, habe ich eine Cron-Warteschlange mit hook_cron_queue_info() wie folgt eingerichtet:

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

Ich fülle die Warteschlange mit dieser Funktion:

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

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

Die Funktion zum Füllen von Warteschlangen wird als Cron-Task aufgerufen. Ich benutze Elysia Cron , also ist meine Implementierung von 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;
}

Die in mymodule_cron_queue_info Definierte Worker-Funktion für jedes Warteschlangenelement lautet wie folgt:

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

Meine Frage ist, wann wird cron tatsächlich mit der Verarbeitung der Warteschlange beginnen?

Angenommen, ich fülle die Warteschlange jeden Tag um 3 Uhr morgens und möchte sie alle 30 Minuten 120 Sekunden lang verarbeiten, bis sie fertig ist. - Muss ich eine weitere Cron-Aufgabe erstellen?

32
joe_flash

Wenn Drupal Cron-Tasks ausführt, werden automatisch alle aus Modulen definierten Cron-Warteschlangen in drupal_cron_run() ; first hook_cron() Implementierungen verarbeitet werden aufgerufen, und dann werden die Cron-Warteschlangen geleert.

Durch Implementieren von hook_cronapi() können Sie einen Eintrag für eine andere Funktion hinzufügen, die die Cron-Warteschlange Ihres Moduls behandelt.

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);
    }
  }
}

Die Alternative besteht darin, Drupal die Cron-Warteschlange für Sie verwalten zu lassen, aber das passiert, wenn Drupal Cron-Aufgaben ausgeführt werden. Wenn Sie die Cron-Warteschlange von Ihnen leeren möchten Modul häufiger können Sie nur eine neue Cron-Aufgabe hinzufügen, die vom Elysia Cron-Modul ausgeführt wird.

Das Elysia Cron-Modul behandelt die Cron-Warteschlangen in elysia_cron_run() ; Diese Funktion wird von elysia_cron_cron() (einer Implementierung von hook_cron()), drush_elysia_cron_run_wrapper() (einem Drush-Befehlsrückruf) und von seinem aufgerufen eigene cron.php . Wenn Sie den Anweisungen in der Datei INSTALL.txt gefolgt sind (insbesondere in "SCHRITT B: SYSTEM CRONTAB ÄNDERN (OPTIONAL)") und den Aufruf von http: // Beispiel) ersetzt haben. com/cron.php mit http://example.com/sites/all/modules/elysia_cron/cron.php sollte das Elysia Cron-Modul bereits die Cron-Warteschlangen verarbeiten. Der von mir vorgeschlagene Code könnte verwendet werden, um die Bearbeitung der von Ihrem Modul verwendeten Cron-Warteschlangen zu beschleunigen, wenn dies tatsächlich erforderlich ist.

// 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();
  }
}
20
kiamlaluno

Die Warteschlange wird zur festgelegten Zeit über den Elysia cronapi-Haken gefüllt.

Die Warteschlange wird jedoch immer dann verarbeitet, wenn der Standard-Cron-Lauf Drupal) ausgeführt wird.

Sehen Sie sich dieses Snippet zur Verarbeitung von Worker-Rückrufen am Ende des Kerns an: 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);
    }
  }
2
David Thomas

wie oben angegeben, werden Ihre Warteschlangen bei Verwendung von Elysia Cron nicht verarbeitet.

sie (und drupal) haben keinen Zugriff auf Warteschlangen, die sonst auf drupal_run_cron ausgeführt würden

die Problemumgehung besteht darin, eine benutzerdefinierte Cron-Aufgabe zu erstellen (dies ist für Elysia Cron sichtbar), um entweder alle oder eine gewünschte Warteschlange zu verarbeiten und dort die Warteschlangenverarbeitung aufzurufen. d.h.

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);
      }
    }
  }
}

jetzt kann die Verarbeitung von Warteschlangen von ElysiaCron gesteuert werden

1
masterperoo

Ich benutze Elysia nicht, aber meine Lösung war schon immer so:

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);
    }
  }
}

Es wird nur ein Element für jeden Cron-Lauf verarbeitet. Vielleicht möchten Sie das ändern.

0
Martin Poulsen

Ich habe auch versucht, mich darum zu kümmern, da ich zum ersten Mal die Warteschlangen-API zusammen mit Elysia Cron verwende. Bei näherer Betrachtung können Sie sehen, dass Elysia cron Warteschlangenelemente ausführt, wenn die Funktion elysia_cron_run aufgerufen wird. Siehe diesen Ausschnitt aus Zeile 1044 in der Datei 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);
    }
  }
}

Dies hat mir geholfen, die Warteschlangenverarbeitung bei Verwendung von Elysia cron zu entmystifizieren.

0
Alex Kirsten