=== modified file 'includes/common.inc' --- includes/common.inc 2009-09-21 07:56:07 +0000 +++ includes/common.inc 2009-09-22 15:02:31 +0000 @@ -3837,6 +3837,11 @@ function drupal_cron_run() { // Fetch the cron semaphore $semaphore = variable_get('cron_semaphore', FALSE); + + $return = FALSE; + // Grab the defined cron queues. + $queues = module_invoke_all('cron_queue'); + drupal_alter('cron_queue', $queues); if ($semaphore) { if (REQUEST_TIME - $semaphore > 3600) { @@ -3853,6 +3858,11 @@ function drupal_cron_run() { } } else { + // 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(); + } // Register shutdown callback register_shutdown_function('drupal_cron_cleanup'); @@ -3870,8 +3880,19 @@ function drupal_cron_run() { variable_del('cron_semaphore'); // Return TRUE so other functions can check if it did run successfully - return TRUE; + $return = TRUE; + } + + 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); + } } + return $return; } /** === modified file 'modules/aggregator/aggregator.module' --- modules/aggregator/aggregator.module 2009-09-18 00:04:21 +0000 +++ modules/aggregator/aggregator.module 2009-09-22 14:55:55 +0000 @@ -306,19 +306,31 @@ function aggregator_permission() { /** * Implement hook_cron(). * - * Checks news feeds for updates once their refresh interval has elapsed. + * Queues news feeds for updates once their refresh interval has elapsed. */ function aggregator_cron() { $result = db_query('SELECT * FROM {aggregator_feed} WHERE checked + refresh < :time AND refresh != :never', array( ':time' => REQUEST_TIME, ':never' => AGGREGATOR_CLEAR_NEVER )); + $queue = DrupalQueue::get('aggregator_feeds'); foreach ($result as $feed) { - aggregator_refresh($feed); + $queue->createItem($feed); } } /** + * Implement hook_cron_queue(). + */ +function aggregator_cron_queue() { + $queues['aggregator_feeds'] = array( + 'worker callback' => 'aggregator_refresh', + 'time' => 60, + ); + return $queues; +} + +/** * Implement hook_block_info(). */ function aggregator_block_info() { === modified file 'modules/aggregator/aggregator.test' --- modules/aggregator/aggregator.test 2009-09-18 00:12:45 +0000 +++ modules/aggregator/aggregator.test 2009-09-20 17:13:57 +0000 @@ -128,7 +128,8 @@ class AggregatorTestCase extends DrupalW */ function updateAndRemove($feed, $expected_count) { $this->updateFeedItems($feed, $expected_count); - $this->assertText('There is new syndicated content from'); + $count = db_query('SELECT COUNT(*) FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->fid))->fetchField(); + $this->assertTrue($count); $this->removeFeedItems($feed); $count = db_query('SELECT COUNT(*) FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->fid))->fetchField(); $this->assertTrue($count == 0); === modified file 'modules/system/system.api.php' --- modules/system/system.api.php 2009-09-19 11:07:36 +0000 +++ modules/system/system.api.php 2009-09-22 15:02:32 +0000 @@ -124,20 +124,49 @@ function hook_entity_info_alter(&$entity * intervals can implement hook_cron(). The engine will then call the hook * at the appropriate intervals defined by the administrator. This interface * is particularly handy to implement timers or to automate certain tasks. - * Database maintenance, recalculation of settings or parameters, and - * automatic mailings are good candidates for cron tasks. + * Database maintenance, recalculation of settings or parameters are good + * candidates for cron tasks. + * Long running tasks should use the queue API, define one or more queues with + * hook_cron_queue() and put items in the queue instead of running them in + * hook_cron(). Examples of jobs that are good candidates for hook_cron_queue + * include automated mailing, retrieving remote data, and intensive file tasks. * * This hook will only be called if cron.php is run (e.g. by crontab). */ function hook_cron() { $result = db_query('SELECT * FROM {site} WHERE checked = 0 OR checked + refresh < :time', array(':time' => REQUEST_TIME)); + $queue = DrupalQueue::get('aggregator_feeds'); foreach ($result as $site) { - cloud_update($site); + $queue->createItem($site); } } /** + * Declare queues holding items that need to be run periodically. + * + * While there can be only one hook_cron() process running at the same time, + * there can be any number of processes defined here running. Because of + * this, long running tasks are much better suited for this API. + * + * @return + * An associative array where the key is the queue name and the value is + * again an associative array. Possible keys are: + * 'worker callback' The name of the function to call. It will be called + * with one argument, the $item from createItem called + * in hook_cron. + * 'time' How much time Drupal should spend on calling this + * worker in seconds. Optional, defaults to 15. + */ +function hook_cron_queue() { + $queues['aggregator_feeds'] = array( + 'worker callback' => 'aggregator_refresh', + 'time' => 15, + ); + return $queues; +} + +/** * Allows modules to declare their own Forms API element types and specify their * default values. *