web-dev-qa-db-ja.com

キューを処理するためにcronタスクが必要ですか?

完了まで約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);
  }
}
_

キュー充填関数は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_で定義された各キューアイテムのワーカー関数は次のようになります。

_function _mymodule_process_user_queue_item($item) {
  //...synchronize user ($item)...
}
_

私の質問は、cronが実際にキューの処理を開始するのはいつですか?

たとえば、毎日午前3時にキューをいっぱいにして、完了するまで30分ごとに120秒処理したい場合-別のcronタスクを作成する必要がありますか?

32
joe_flash

Drupalがcronタスクを実行すると、モジュールから定義されたすべてのcronキューが drupal_cron_run() ;最初の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.phpINSTALL.txt ファイルの指示(特に「ステップB:変更システムのCRONTAB(オプション)」)に従い、 http:// example。 com/cron.phphttp://example.com/sites/all/modules/elysia_cron/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();
  }
}
_
20
kiamlaluno

キューは、設定された時間に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);
    }
  }
2
David Thomas

前述のとおり、Elysia Cronを使用する場合、キューは処理されません。

あなた(およびdrupal)は、他の方法ではdrupal_run_cronで実行されるキューにアクセスできません。

回避策は、カスタムcronタスク(これはelysia cronに表示されます)を作成して、すべてのキューまたは必要なキューを処理し、そこでキュー処理を呼び出すことです。つまり:

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

キューの処理をElysiaCronで制御できるようになりました

1
masterperoo

私はエリシアを使用しませんが、私の解決策は常に次のようなものでした:

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

Cronの実行ごとに1つのアイテムのみを処理します。多分あなたはそれを変えたいです。

0
Martin Poulsen

Elysia cronと共に初めてQueue APIを使用しているので、これにも頭を悩ませています。詳細に調べると、関数elysia_cron_runが呼び出されたときにElysia cronがキューアイテムを実行していることがわかります。ファイルelysia_cron.module内のline 1044からこのスニペットを参照してください:

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

これは、Elysia cronを使用するときにキュー処理をわかりやすくするのに役立ちました。

0
Alex Kirsten