Apakah saya memerlukan tugas cron untuk memproses antrian?


32

Saya punya tugas yang membutuhkan waktu sekitar 45 menit untuk diselesaikan dan perlu terjadi setiap hari (menyinkronkan pengguna ke beberapa basis data eksternal, dll).

Untuk menangani pekerjaan, saya telah menyiapkan antrian cron dengan hook_cron_queue_info()sebagai berikut:

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

Saya mengisi antrian menggunakan fungsi ini:

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

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

Fungsi mengisi antrian dipanggil sebagai tugas cron. Saya menggunakan Elysia Cron , jadi implementasi saya hook_cronapi()adalah:

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

Fungsi pekerja untuk setiap item antrian, didefinisikan dalam mymodule_cron_queue_infoseperti:

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

Pertanyaan saya adalah, kapan sebenarnya cron akan mulai memproses antrian?

Katakanlah saya mengisi antrian setiap hari jam 3 pagi, dan ingin memprosesnya 120 detik dari setiap 30 menit sampai selesai - apakah saya perlu membuat tugas cron lain?


Saya harus menyebutkan saya menggunakan Drupal 7.
joe_flash

1
Saya juga ingin tahu tentang pertanyaan ini. Ingin mendengar ya atau tidak. Kami menggunakan API antrian berat di salah satu proyek D7 kami. Secara visual saya telah melihat baris tabel {queue} dihapus ketika cron berjalan. Jadi anggaplah itu ya.
Sivaji

Jawaban:


19

Ketika Drupal menjalankan tugas cron, secara otomatis menangani setiap antrian cron yang ditentukan dari modul, di drupal_cron_run(); hook_cron()implementasi pertama dipanggil, dan kemudian antrian cron dikosongkan.

Dalam penerapan hook_cronapi(), Anda dapat menambahkan entri untuk fungsi lain yang menangani antrian cron modul Anda.

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

Alternatifnya adalah membiarkan Drupal menangani antrian cron untuk Anda, tetapi itu terjadi ketika tugas-tugas cron Drupal dijalankan. Jika Anda ingin mengosongkan antrian cron modul Anda lebih sering, Anda hanya dapat menambahkan tugas cron baru yang ditangani oleh modul Elysia Cron.

Modul Elysia Cron menangani antrian cron di elysia_cron_run(); fungsi ini dipanggil dari elysia_cron_cron()(suatu implementasi dari hook_cron()), drush_elysia_cron_run_wrapper()(sebuah perintah callback Drush), dan dari cron.php -nya sendiri . Jika Anda mengikuti petunjuk dalam file INSTALL.txt (khususnya dalam "LANGKAH B: MENGUBAH SISTEM CRONTAB (OPTIONAL)"), dan mengganti setiap pemanggilan dari http://example.com/cron.php dengan http: // contoh .com / sites / all / modules / elysia_cron / cron.php , modul Elysia Cron harus sudah menangani antrian cron. Kode yang saya sarankan dapat digunakan untuk mempercepat penanganan antrian cron yang digunakan dari modul Anda, jika perlu secara efektif.

// 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, terima kasih @kiam! Itu yang saya curigai, tetapi saya tidak bisa membayangkannya.
joe_flash

Sebenarnya, saya pikir saya kehilangan sesuatu di sini. Anda bilang alternatifnya adalah membiarkan Drupal menangani antrian cron untuk saya; Saya kira sebagian dari pertanyaan awal saya adalah kapan itu benar-benar terjadi ? Setiap kali permintaan crontab cron.php? Jika itu masalahnya, itu terjadi setiap menit (lihat komentar pertama saya di @ David's reply).
joe_flash

1
Perlu disebutkan bahwa Elysia cron memiliki implementasi prosesor cron_queue sendiri elysia_cron_rundengan antrian cron diproses secara otomatis setiap kali Elysia's cron.php diminta.
David Thomas

@ joe_flash Saya minta maaf: Seharusnya saya lebih jelas. Ya, Drupal menjalankan tugas cron ketika cron.php dipanggil (untuk setiap versi Drupal hingga Drupal 7). Di Drupal 8, cron.php tidak ada lagi, dan tugas cron dieksekusi menggunakan jalur sistem yang berbeda.
kiamlaluno

2

Antrian akan diisi melalui kait cronapi Elysia pada waktu yang ditentukan.

Namun, antrian akan diproses setiap kali dijalankan standar cron Drupal.

Lihat potongan pemrosesan panggilan balik pekerja ini di akhir inti: 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, mungkin Elysia memperkenalkan sedikit masalah di sini? Saya telah menetapkan crontab untuk memicu cron.phpskrip Elysia setiap menit , yang memungkinkan Elysia untuk mengontrol waktu tugas dengan resolusi menit-bijaksana. Tidak ada tugas yang benar-benar berjalan setiap menit - yang membuat saya berpikir saya perlu membuat tugas untuk secara khusus bekerja pada antrian?
joe_flash

@joe_flash selama drupal_cron_rundipanggil, panggilan balik pekerja antrian cron Anda akan diproses.
David Thomas

Ah, saya pikir Anda benar. Namun, drupal_cron_runtidak dipanggil dari cron.phpskrip Elysia (saat Elysia diaktifkan); elysia_cron_rundigunakan sebagai gantinya.
joe_flash

Dalam hal ini, sepertinya Anda tidak dapat menggunakan hook_cron_queue_infodengan Elysia cron, kecuali jika Anda menetapkan panggilan balik pekerja Anda sendiri, seperti drupal_cron_runcuplikan fungsi inti di atas.
David Thomas

elysia_cron_runtidak menelepon drupal_cron_run, tetapi memang memanggil module_invoke_all('cron_queue_info')dan melakukan beberapa penanganan multi-channel yang membuat asap keluar dari telinga saya.
joe_flash

1

seperti yang dinyatakan di atas ketika menggunakan Elysia Cron antrian Anda tidak diproses.

Anda (dan drupal) tidak memiliki akses ke antrian yang seharusnya berjalan di drupal_run_cron

solusinya adalah membuat tugas cron khusus - (ini akan terlihat oleh elysia cron) untuk memproses semua antrian atau yang Anda inginkan dan menjalankan pemrosesan antrian di sana. yaitu:

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

sekarang pemrosesan antrian dapat dikontrol oleh ElysiaCron


0

Saya tidak menggunakan Elysia, tetapi solusi saya selalu seperti ini:

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

Ini hanya menangani satu item, untuk setiap cron run. Mungkin Anda ingin mengubahnya.


0

Saya juga telah mencoba membungkus kepala saya di sekitar ini, karena saya menggunakan Antrian API untuk pertama kalinya bersama dengan Elysia cron. Setelah pemeriksaan lebih dekat, Anda dapat melihat bahwa Elysia cron mengeksekusi item antrian ketika fungsi elysia_cron_run dipanggil. Lihat cuplikan ini dari baris 1044 dalam 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);
    }
  }
}

Ini membantu melegitimasi pemrosesan antrian untuk saya ketika menggunakan Elysia cron.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.