当前位置: 首页>>网站问题>>正文


我是否需要cron任务来处理队列?

webfans 网站问题 , , , , 去评论

问题描述

我有一项任务需要大约45分钟才能完成,并且需要每天进行(将用户同步到多个外部数据库等)。

为了处理这项工作,我使用hook_cron_queue_info()设置了一个cron队列,如下所示:

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

我使用这个函数填充队列:

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

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

queue-filling函数被称为cron任务。我使用Elysia Cron,所以我对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;
}

mymodule_cron_queue_info中定义的每个队列项的worker函数如下:

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

我的问题是,cron什么时候开始处理队列?

假设我每天凌晨3点填满队列,并希望每30分钟处理120秒,直到完成为止 – 我是否需要创建另一个cron任务?

最佳解决办法

当Drupal运行cron任务时,它会在drupal_cron_run()中自动处理从模块定义的任何cron队列;首先调用hook_cron()实现,然后清空cron队列。

在实现hook_cronapi()时,您可以为处理模块的cron队列的另一个函数添加一个条目。

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

另一种方法是让Drupal为你处理cron队列,但是当执行Drupal cron任务时会发生这种情况。如果要更频繁地清空模块的cron队列,则只能添加由Elysia Cron模块处理的新cron任务。

Elysia Cron模块处理elysia_cron_run()中的cron队列;此函数正在从elysia_cron_cron()(hook_cron()的实现),drush_elysia_cron_run_wrapper()(Drush命令回调)以及它自己的cron.php中调用。如果您按照INSTALL.txt文件中的说明进行操作(特别是在“步骤B:更改系统CRONTAB(可选)”中),并用http://example.com/sites/all/modules/elysia_cron/cron.php替换了http://example.com/cron.php的任何调用,则Elysia Cron模块应该已经在处理cron队列。如果有效地需要这样做,我建议的代码可用于加速处理模块中使用的cron队列。

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

次佳解决办法

队列将在设定的时间通过Elysia cronapi钩子填充。

但是,只要发生标准Drupal cron运行,就会处理队列。

请参阅核心末尾的此工作程序回调处理代码段: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);
    }
  }

参考资料

本文由朵颐IT整理自网络, 文章地址: https://duoyit.com/article/2621.html,转载请务必附带本地址声明。