Tôi có cần một tác vụ cron để xử lý hàng đợi không?


32

Tôi đã có một nhiệm vụ mất khoảng 45 phút để hoàn thành và cần phải thực hiện mỗi ngày (đồng bộ hóa người dùng với một số cơ sở dữ liệu bên ngoài, v.v.).

Để xử lý công việc, tôi đã thiết lập một hàng đợi cron hook_cron_queue_info()như sau:

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

Tôi điền vào hàng đợi bằng chức năng này:

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

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

Hàm điền hàng đợi được gọi là tác vụ cron. Tôi sử dụng Elysia Cron , vì vậy việc thực hiện của tôi hook_cronapi()là:

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

Hàm worker cho mỗi mục hàng đợi, được định nghĩa trong mymodule_cron_queue_infonhư:

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

Câu hỏi của tôi là, khi nào thì cron thực sự sẽ bắt đầu xử lý hàng đợi?

Giả sử tôi điền hàng đợi mỗi ngày vào lúc 3 giờ sáng và muốn xử lý 120 giây sau mỗi 30 phút cho đến khi hoàn thành - tôi có cần tạo một tác vụ cron khác không?


Tôi nên đề cập đến việc tôi đang sử dụng Drupal 7.
joe_flash

1
Tôi cũng tò mò về câu hỏi này. Muốn nghe có hay không. Chúng tôi sử dụng API hàng đợi rất nhiều trong một trong các dự án D7 của chúng tôi. Trực quan tôi đã thấy các hàng của bảng {queue} bị xóa khi cron chạy. Vì vậy, giả sử nó là có.
Sivaji

Câu trả lời:


19

Khi Drupal chạy các tác vụ cron, nó sẽ tự động xử lý bất kỳ hàng đợi cron nào được xác định từ các mô-đun, trong drupal_cron_run(); hook_cron()triển khai đầu tiên được gọi, và sau đó hàng đợi cron được làm trống.

Đang thực hiện hook_cronapi(), bạn có thể thêm một mục nhập cho một chức năng khác xử lý hàng đợi cron của mô-đun của bạn.

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

Cách khác là để Drupal xử lý hàng đợi cron cho bạn, nhưng điều đó xảy ra khi các tác vụ cron Drupal được thực thi. Nếu bạn muốn làm trống hàng đợi cron của mô-đun của bạn thường xuyên hơn, bạn chỉ có thể thêm một tác vụ cron mới được xử lý bởi mô-đun Elysia Cron.

Mô-đun Elysia Cron xử lý các hàng đợi cron trong elysia_cron_run(); Chức năng này đang được gọi từ elysia_cron_cron()(một thực hiện hook_cron()), drush_elysia_cron_run_wrapper()(một lệnh Drush gọi lại), và từ riêng của mình cron.php . Nếu bạn đã làm theo các hướng dẫn trong tệp INSTALL.txt (cụ thể là trong "BƯỚC B: THAY ĐỔI HỆ THỐNG CRONTAB (TÙY CHỌN)") và thay thế bất kỳ lời mời nào của http://example.com/cron.php bằng http: // ví dụ .com / site / all / module / elysia_cron / cron.php , mô-đun Elysia Cron nên đã xử lý các hàng đợi cron. Mã tôi đề xuất có thể được sử dụng để tăng tốc độ xử lý hàng đợi cron được sử dụng từ mô-đun của bạn, nếu thực sự cần phải làm như vậy.

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

À, cảm ơn @kiam! Đó là những gì tôi nghi ngờ, nhưng tôi không thể bao bọc bộ não của mình xung quanh nó.
joe_flash

Trên thực tế, tôi nghĩ rằng tôi đang thiếu một cái gì đó ở đây. Bạn nói phương án thay thế là để Drupal xử lý hàng đợi cron cho tôi; Tôi đoán một phần của câu hỏi ban đầu của tôi là khi điều đó thực sự xảy ra ? Mỗi lần crontab yêu cầu cron.php? Nếu đó là trường hợp, điều đó xảy ra mỗi phút (xem bình luận đầu tiên của tôi về câu trả lời của @ David).
joe_flash

1
Điều đáng nói là có vẻ như Elysia cron có bộ xử lý cron_queue riêng elysia_cron_runvới hàng đợi cron được xử lý tự động mỗi khi cron.php của Elysia được yêu cầu.
David Thomas

@joe_flash Tôi xin lỗi: Đáng lẽ tôi phải rõ ràng hơn. Có, Drupal chạy các tác vụ cron khi cron.php được gọi (cho mọi phiên bản Drupal cho đến Drupal 7). Trong Drupal 8, cron.php không xuất hiện nữa và các tác vụ cron được thực thi bằng một đường dẫn hệ thống khác.
kiamlaluno

2

Hàng đợi sẽ được điền thông qua móc cronapi Elysia tại thời điểm đã đặt.

Tuy nhiên, hàng đợi sẽ được xử lý bất cứ khi nào chạy cron Drupal tiêu chuẩn.

Xem đoạn mã xử lý gọi lại của nhân viên này ở cuối lõi: 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, có lẽ Elysia giới thiệu một chút phức tạp ở đây? Tôi đã thiết lập crontab để kích hoạt cron.phptập lệnh Elysia mỗi phút , cho phép Elysia kiểm soát thời gian thực hiện với độ phân giải tối thiểu. Không có nhiệm vụ nào thực sự chạy mỗi phút mặc dù - đó là điều khiến tôi nghĩ rằng tôi cần phải tạo ra một nhiệm vụ để đặc biệt làm việc trên hàng đợi?
joe_flash

@joe_flash miễn drupal_cron_runlà được gọi, cuộc gọi lại nhân viên hàng đợi cron của bạn sẽ được xử lý.
David Thomas

Ah, tôi nghĩ bạn đúng. Tuy nhiên, drupal_cron_runkhông được gọi từ cron.phptập lệnh Elysia (khi Elysia được bật); elysia_cron_runđược sử dụng thay thế.
joe_flash

Trong trường hợp đó, có vẻ như bạn không thể sử dụng hook_cron_queue_infovới Elysia cron, trừ khi bạn chỉ định cuộc gọi lại công nhân của riêng bạn, theo drupal_cron_runđoạn mã chức năng cốt lõi ở trên.
David Thomas

elysia_cron_runkhông gọi drupal_cron_run, nhưng nó không gọi module_invoke_all('cron_queue_info')và thực hiện một số fancy-quần xử lý mà làm cho hút thuốc đi ra tai tôi đa kênh.
joe_flash

1

như đã nêu ở trên khi sử dụng Elysia Cron, hàng đợi của bạn không được xử lý.

bạn (và drupal) không có quyền truy cập vào các hàng đợi chạy trên drupal_run_cron

cách giải quyết là tạo một tác vụ cron tùy chỉnh - (điều này sẽ hiển thị với elysia cron) để xử lý tất cả các hàng đợi hoặc một thứ bạn muốn và gọi xử lý hàng đợi ở đó. I E:

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

bây giờ việc xử lý hàng đợi có thể được kiểm soát bởi ElysiaCron


0

Tôi không sử dụng Elysia, nhưng giải pháp của tôi luôn là như thế này:

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

Nó chỉ xử lý một mục, cho mỗi lần chạy cron. Có lẽ bạn muốn thay đổi điều đó.


0

Tôi cũng đã cố gắng che giấu điều này vì lần đầu tiên tôi sử dụng API xếp hàng cùng với Elysia cron. Khi kiểm tra kỹ hơn, bạn có thể thấy rằng Elysia cron thực thi các mục hàng đợi khi hàm elysia_cron_run được gọi. Xem đoạn trích này từ dòng 1044 trong tệp 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);
    }
  }
}

Điều này giúp làm sáng tỏ quá trình xử lý hàng đợi cho tôi khi sử dụng cron Elysia.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.