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


32

完了までに約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タスクを作成する必要がありますか?


Drupal 7を使用していることに言及する必要があります。
joe_flash13年

1
私もこの質問に興味があります。yesまたはnoを聞きたいです。D7プロジェクトの1つでキューAPIを多用しています。視覚的には、cronの実行時に{queue}テーブルの行がクリアされるのを見てきました。だからそれはイエスだと思います。
シヴァジ

回答:


19

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モジュールはcronキューを処理しますelysia_cron_run(); この関数は、elysia_cron_cron()(の実装hook_cron())、drush_elysia_cron_run_wrapper()(Drushコマンドコールバック)、および独自のcron.phpから呼び出されています。あなたはの指示に従っていればいるinstall.txtファイル(に特にを「STEPのB:CHANGE SYSTEM CRONTAB(オプション)」)、および任意の呼び出しに置き換えhttp://example.com/cron.phpをます。http://例.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();
  }
}

ああ、ありがとう@kiam!それは私が疑ったことですが、私はそれを自分の脳で完全に包むことができませんでした。
-joe_flash

実際、私はここで何かを見逃していると思います。代替案は、Drupalにcronキューを処理させることです。私の最初の質問の一部は、いつ実際にそれが起こるのでしょか?crontabが要求するたびにcron.php?その場合、毎分発生します(@Davidの返信に関する私の最初のコメントを参照)。
-joe_flash

1
Elysia cronには、elysia_cron_runElysiaのcron.phpが要求されるたびにcronキューが自動的に処理される、独自のcron_queueプロセッサ実装が含まれているように見えることに注意してください。
デビッドトーマス

@joe_flash申し訳ありませんが、私はもっと明確にすべきでした。はい、Drupalはcron.phpが呼び出されたときにcronタスクを実行します(Drupal 7までのすべてのDrupalバージョンに対して)。Drupal 8では、cron.phpはもう存在せず、cronタスクは異なるシステムパスを使用して実行されます。
キアムルノ

2

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

デビッド、おそらくエリシアはここで少し複雑なことを紹介していますか?Elysia cron.phpスクリプトを毎分トリガーするようにcrontabを設定しました。これにより、Elysiaは分単位の解像度でタスク時間を制御できます。ただし、実際には毎分実行されるタスクはありません。これが、キューで具体的に動作するタスクを作成する必要があると私に思わせた理由です。
-joe_flash

@joe_flashが呼び出されている限りdrupal_cron_run、cronキューワーカーコールバックが処理されます。
デビッドトーマス

ああ、私はあなたが正しいと思う。ただし、drupal_cron_runElysia cron.phpスクリプトからは呼び出されません(Elysiaが有効な場合)。elysia_cron_run代わりに使用されます。
joe_flash

その場合、上記のhook_cron_queue_infoコアdrupal_cron_run関数スニペットに従って独自のワーカーコールバックを指定しない限り、Elysia cronで使用できないようです。
デビッドトーマス

elysia_cron_run呼び出すことはありませんdrupal_cron_runが、それはありません通話をmodule_invoke_all('cron_queue_info')して、いくつかの派手なパンツのマルチチャンネルが行うが、私の耳を出て喫煙することを取り扱いありません。
joe_flash

1

前述のように、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で制御できるようになりました


0

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

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

また、Elysia cronと一緒に初めてQueue APIを使用しているので、これに頭を悩ませようとしています。よく見ると、関数elysia_cron_runが呼び出されたときにElysia cronがキューアイテムを実行していることがわかります。ファイルelysia_cron.module内の行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を使用する際のキュー処理を分かりやすく説明するのに役立ちました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.