ฉันต้องการงาน cron เพื่อประมวลผลคิวหรือไม่?


32

ฉันมีงานที่ต้องใช้เวลาดำเนินการประมาณ 45 นาทีและต้องเกิดขึ้นทุกวัน (เชื่อมข้อมูลผู้ใช้กับฐานข้อมูลภายนอกหลายแห่งและอื่น ๆ )

เพื่อจัดการงานฉันได้ตั้งค่าคิว cron ด้วยhook_cron_queue_info()ดังนี้

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 และต้องการประมวลผล 120 วินาทีจากทุก ๆ 30 นาทีจนกว่าจะเสร็จ - ฉันต้องสร้างงาน cron อีกหรือไม่


ฉันควรจะพูดถึงว่าฉันใช้ Drupal 7
joe_flash

1
ฉันอยากรู้เกี่ยวกับคำถามนี้ อยากได้ยินใช่หรือไม่ เราใช้ API คิวอย่างมากในโครงการ D7 ของเรา เห็นได้ชัดว่าฉันเห็น {คิว} แถวของตารางจะถูกล้างเมื่อ cron ทำงาน สมมติว่าเป็นใช่
Sivaji

คำตอบ:


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 ของโมดูลของคุณบ่อยขึ้นคุณสามารถเพิ่มภารกิจ cron ใหม่ที่จัดการโดยโมดูล Elysia Cron เท่านั้น

โมดูล Elysia Cron จัดการคิว cron ในelysia_cron_run(); ฟังก์ชั่นนี้จะถูกเรียกจากelysia_cron_cron()(การดำเนินการhook_cron()) drush_elysia_cron_run_wrapper()(ก Drush คำสั่งการเรียกกลับ) และจากของตัวเองcron.php หากคุณทำตามคำแนะนำในไฟล์INSTALL.txt (โดยเฉพาะใน "ขั้นตอน B: เปลี่ยนระบบ 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 มีการประมวลผล cron_queue ของตัวเองในการที่elysia_cron_runมีคิว cron จะถูกประมวลผลโดยอัตโนมัติทุกครั้งที่มีการร้องขอ cron.php ของ Elysia
เดวิดโธมัส

@joe_flash ฉันขอโทษ: ฉันควรจะชัดเจนขึ้น ใช่ Drupal เรียกใช้งาน cron เมื่อมีการเรียก cron.php (สำหรับทุกรุ่นของ Drupal จนถึง Drupal 7) ใน Drupal 8 cron.php จะไม่ปรากฏอีกต่อไปและงาน cron จะถูกดำเนินการโดยใช้เส้นทางของระบบที่แตกต่างกัน
kiamlaluno

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

เดวิดบางทีเอลีเซียแนะนำภาวะแทรกซ้อนเล็กน้อยที่นี่? ฉันได้ตั้งค่า crontab เพื่อทริกเกอร์cron.phpสคริปต์Elysia ทุกนาทีซึ่งช่วยให้ Elysia สามารถควบคุมเวลางานได้ด้วยความละเอียดที่ชาญฉลาด ไม่มีงานใดทำงานจริงทุกนาที - อะไรทำให้ฉันคิดว่าฉันต้องสร้างงานเพื่อทำงานบนคิวโดยเฉพาะ?
joe_flash

@joe_flash ตราบใดที่drupal_cron_runมีการโทรติดต่อผู้ปฏิบัติงานคิว cron ของคุณจะถูกประมวลผล
David Thomas

อ่าฉันคิดว่าคุณพูดถูก อย่างไรก็ตามdrupal_cron_runไม่ได้รับการเรียกจากcron.phpสคริปต์Elysia (เมื่อเปิดใช้งาน Elysia) elysia_cron_runใช้แทน
joe_flash

ในกรณีนี้ดูเหมือนว่าคุณจะไม่สามารถใช้hook_cron_queue_infoกับ Elysia cron ได้เว้นแต่คุณจะระบุการโทรกลับของพนักงานของคุณเองตามdrupal_cron_runตัวอย่างฟังก์ชันหลักด้านบน
David Thomas

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

ฉันไม่ได้ใช้ Elysia แต่โซลูชันของฉันเป็นแบบนี้มาตลอด:

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 แต่ละครั้ง บางทีคุณอาจต้องการเปลี่ยนแปลงสิ่งนั้น


0

ฉันได้พยายามห่อหัวของฉันรอบนี้เนื่องจากฉันใช้ Queue API เป็นครั้งแรกพร้อมกับ Elysia cron เมื่อตรวจสอบอย่างใกล้ชิดคุณจะเห็นว่า Elysia รัน cron คิวรายการเมื่อฟังก์ชั่นelysia_cron_runเรียกว่า ดูตัวอย่างนี้จากบรรทัด 1044ภายในไฟล์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);
    }
  }
}

สิ่งนี้ช่วยลดความซับซ้อนของการประมวลผลคิวสำหรับฉันเมื่อใช้ Elysia cron

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.