完了まで約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が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.php 。 INSTALL.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();
}
}
_
キューは、設定された時間に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を使用する場合、キューは処理されません。
あなた(および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で制御できるようになりました
私はエリシアを使用しませんが、私の解決策は常に次のようなものでした:
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つのアイテムのみを処理します。多分あなたはそれを変えたいです。
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を使用するときにキュー処理をわかりやすくするのに役立ちました。