it-swarm-vi.com

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

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 hàng đợi cron với 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 triển khai hook_cronapi() của tôi 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 từng mục hàng đợi, được xác định trong mymodule_cron_queue_info Giống như:

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?

32
joe_flash

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() ; đầu tiên hook_cron() triển khai được gọi, và sau đó các hàng cron được làm trống.

Khi 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à cho phép Drupal xử lý hàng đợi cron cho bạn, nhưng điều đó xảy ra khi Drupal tác vụ cron được thực thi. Nếu bạn muốn làm trống hàng đợi cron của bạn mô-đun 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 cron trong elysia_cron_run() ; hàm này đang được gọi từ elysia_cron_cron() (triển khai hook_cron()), drush_elysia_cron_run_wrapper() (gọi lại lệnh Drush) và từ nó riêng 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 ví dụ http: //. com/cron.php với http://example.com/sites/all/modules/elysia_cron/cron.php , mô-đun Elysia Cron nên đã xử lý 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();
  }
}
20
kiamlaluno

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 tiêu chuẩn Drupal cron chạy xảy ra.

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);
    }
  }
2
David Thomas

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 ra 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

1
masterperoo

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
Martin Poulsen

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.

0
Alex Kirsten