=== modified file 'includes/common.inc'
--- includes/common.inc	2009-09-18 10:54:20 +0000
+++ includes/common.inc	2009-09-18 22:05:33 +0000
@@ -3838,6 +3838,8 @@ function drupal_cron_run() {
 
   // Fetch the cron semaphore
   $semaphore = variable_get('cron_semaphore', FALSE);
+  
+  $return = FALSE;
 
   if ($semaphore) {
     if (REQUEST_TIME - $semaphore > 3600) {
@@ -3871,8 +3873,18 @@ 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 (module_implements('cron_worker') as $module) {
+    $function = $module . '_cron_worker';
+    $end = time() + variable_get($function, 15);
+    $queue = DrupalQueue::get($function);
+    while (time() < $end && ($item = $queue->claimItem())) {
+      $function($item->data);
+      $queue->deleteItem($item);
+    }
+  }
+  return $return;
 }
 
 /**

=== modified file 'modules/aggregator/aggregator.install'
--- modules/aggregator/aggregator.install	2009-09-10 06:38:16 +0000
+++ modules/aggregator/aggregator.install	2009-09-16 03:31:42 +0000
@@ -7,6 +7,13 @@
  */
 
 /**
+ * Implement hook_install().
+ */
+function aggregator_install() {
+  DrupalQueue::get('aggregator_cron_worker')->createQueue();
+}
+
+/**
  * Implement hook_uninstall().
  */
 function aggregator_uninstall() {

=== modified file 'modules/aggregator/aggregator.module'
--- modules/aggregator/aggregator.module	2009-09-18 00:04:21 +0000
+++ modules/aggregator/aggregator.module	2009-09-18 02:56:25 +0000
@@ -306,19 +306,29 @@ 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_cron_worker');
   foreach ($result as $feed) {
-    aggregator_refresh($feed);
+    $queue->createItem($feed);
   }
 }
 
 /**
+ * Implement hook_cron_worker().
+ *
+ * Refresh queued news feeds.
+ */
+function aggregator_cron_worker($feed) {
+  aggregator_refresh($feed);
+}
+
+/**
  * 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-18 02:56:25 +0000
@@ -94,7 +94,7 @@ class AggregatorTestCase extends DrupalW
     $this->assertResponse(200, t('!url is reachable.', array('!url' => $feed->url)));
 
     // Refresh the feed (simulated link click).
-    $this->drupalGet('admin/config/services/aggregator/update/' . $feed->fid);
+    drupal_cron_run();
 
     // Ensure we have the right number of items.
     $result = db_query('SELECT iid FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->fid));
@@ -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);
@@ -396,7 +397,7 @@ class UpdateFeedItemTestCase extends Agg
     $this->assertRaw(t('The feed %name has been added.', array('%name' => $edit['title'])), t('The feed !name has been added.', array('!name' => $edit['title'])));
 
     $feed = db_query("SELECT * FROM {aggregator_feed} WHERE url = :url", array(':url' => $edit['url']))->fetchObject();
-    $this->drupalGet('admin/config/services/aggregator/update/' . $feed->fid);
+    drupal_cron_run();
 
     $before = db_query('SELECT timestamp FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->fid))->fetchField();
 
@@ -411,7 +412,7 @@ class UpdateFeedItemTestCase extends Agg
         'modified' => 0,
       ))
       ->execute();
-    $this->drupalGet('admin/config/services/aggregator/update/' . $feed->fid);
+    drupal_cron_run();
 
     $after = db_query('SELECT timestamp FROM {aggregator_item} WHERE fid = :fid', array(':fid' => $feed->fid))->fetchField();
 

=== modified file 'modules/system/system.api.php'
--- modules/system/system.api.php	2009-09-18 00:04:21 +0000
+++ modules/system/system.api.php	2009-09-18 22:06:16 +0000
@@ -124,20 +124,40 @@ 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 and hook_cron_worker().
+ * Automatic mailings, retrieval of remote data are good examples of what
+ * should be done in hook_cron_worker() instead.
  *
  * 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));
+  // Don't forget to replace hook with the module name in the queue name.
+  $queue = DrupalQueue::get('hook_cron_worker');
 
   foreach ($result as $site) {
-    cloud_update($site);
+    $queue->createItem($site);
   }
 }
 
 /**
+ * Perform long running periodic actions.
+ *
+ * While there can be only one hook_cron() process running at the same time,
+ * there can be any number of hook_cron_worker() processes running. Because of
+ * this, long running tasks are much better suited for hook_cron_worker.
+ *
+ * @param $item
+ *   An item from the queue hook_cron_worker, where hook is replaced by the
+ *   module name, same as in function names.
+ */
+function hook_cron_worker($item) {
+  cloud_update($item);
+}
+
+/**
  * Allows modules to declare their own Forms API element types and specify their
  * default values.
  *

