diff --git a/cron/hosting_cron.module b/cron/hosting_cron.module
index 241eaf7..b13008f 100644
--- a/cron/hosting_cron.module
+++ b/cron/hosting_cron.module
@@ -6,17 +6,16 @@
 
 /**
  * Implements hook_hosting_queues().
+ *
+ * @todo: In Hosting 4.x change the type to HOSTING_QUEUE_TYPE_SPREAD.
  */
 function hosting_cron_hosting_queues() {
   $items['cron'] = array(
-    'type' => 'batch',
+    'type' => HOSTING_QUEUE_TYPE_BATCH,
     'name' => t('Cron queue'),
     'description' => t('Run cron on hosted sites.'),
     'total_items' => hosting_site_count(),
     'frequency' => strtotime("1 hour", 0),
-    'min_threads' => 6,
-    'max_threads' => 12,
-    'threshold' => 100,
     'singular' => t('site'),
     'plural' => t('sites'),
   );
diff --git a/hosting.api.php b/hosting.api.php
index 138b71a..e589a6f 100644
--- a/hosting.api.php
+++ b/hosting.api.php
@@ -132,13 +132,57 @@ function hook_hosting_feature() {
 /**
  * Define hosting queues.
  *
- * @see hosting_get_queues()
+ * @see hosting_get_queues
  */
 function hook_hosting_queues() {
 
 }
 
 /**
+ * Alter module defined queue definitions before they are processed.
+ *
+ * This hook is invoked before hosting calculates the number of items to
+ * process when processing queues, so, for example, you could alter the number of apparent
+ * items in the queue.
+ *
+ * @param array $queues
+ *   The array of queue definitions of queues provided by modules.
+ *
+ * @see hosting_get_queues
+ * @see hook_hosting_queues
+ * @see hook_hosting_processed_queues_alter
+ */
+function hook_hosting_queues_alter(&$queues) {
+  if (isset($queues['cron'])) {
+    // Do not execute the cron queue at weekends.
+    if (date('N', REQUEST_TIME) > 5) {
+      $queues['cron']['total_items'] = 0;
+    }
+  }
+}
+
+/**
+ * Alter module defined queue definitions after they are processed.
+ *
+ * This hook is invoked after hosting module calculates the number of items to
+ * process when processing queues, and after the configurable information has
+ * been merged in.
+ *
+ * @param array $queues
+ *   The processed array of queue definitions of queues provided by modules.
+ *
+ * @see hosting_get_queues
+ * @see hook_hosting_queues
+ * @see hook_hosting_queues_alter
+ */
+function hook_hosting_processed_queues_alter(&$queues) {
+  if (isset($queues['cron'])) {
+    // Force the cron queue to always be disabled.
+    $queues['cron']['enabled'] = FALSE;
+  }
+}
+
+/**
  * Add or change context options before a hosting task runs.
  *
  * This hook is invoked just before any task that has the 'provision_save' flag
diff --git a/hosting.module b/hosting.module
index 7140cba..a5fcf63 100644
--- a/hosting.module
+++ b/hosting.module
@@ -14,6 +14,53 @@
 define('HOSTING_MAX_ALIAS_LENGTH', 235);
 
 /**
+ * A serial queue type.
+ *
+ * This queue will be processed at a specified interval. When the interval has
+ * elapsed a configurable number of the items will be processed.
+ */
+define('HOSTING_QUEUE_TYPE_SERIAL', 'serial');
+
+/**
+ * A batch queue type,
+ *
+ * This queue type aims to process repeatable tasks spread out over a
+ * configurable interval.
+ *
+ * See the processing code in hosting_get_queues() for the exact
+ * implementation.
+ *
+ * This queue type will:
+ * - Process items in the queue at some small number of specific points, evenly spaced throughout
+ *   the configurable interval.
+ * - Process as many items at those intervals so that all the items are
+ *   processed at least once over the configurable interval.
+ *
+ * @see HOSTING_QUEUE_TYPE_PARALLEL
+ */
+define('HOSTING_QUEUE_TYPE_BATCH', 'batch');
+
+/**
+ * A parallel queue type,
+ *
+ * This queue type aims to process repeatable tasks spread out over a
+ * configurable interval.
+ *
+ * See the processing code in hosting_get_queues() for the exact
+ * implementation.
+ *
+ * This queue type will attempt to:
+ * - Process items at as many points as possible evenly spread over the
+ *   configurable interval.
+ * - Points will be at least 1 minute apart to allow for the default dispatcher to execute them.
+ * - At each point process the minimum number of items needed to result in all
+ *   items being processed at least once over the configurable interval.
+ *
+ * @see HOSTING_QUEUE_TYPE_BATCH
+ */
+define('HOSTING_QUEUE_TYPE_SPREAD', 'spread');
+
+/**
  * Not split for performance reasons. Just to keep code together.
  */
 include_once dirname(__FILE__) . '/hosting.inc';
@@ -859,7 +906,17 @@ function hosting_queues_configure($form, &$form_state) {
     $form[$queue]['frequency']['#prefix'] = "<div class='hosting-queue-frequency'>";
     $form[$queue]['frequency']['#suffix'] = "</div>";
 
-    if ($info['type'] == 'batch') {
+    if ($info['type'] == HOSTING_QUEUE_TYPE_BATCH) {
+      $form[$queue]['frequency']['items'] = array(
+        '#markup' => t('%count %items every', array(
+          "%count" => $info['total_items'],
+          "%items" => format_plural($info['total_items'], $info['singular'], $info['plural']),
+        )),
+        '#prefix' => "<div class='hosting-queue-frequency-items'>",
+        '#suffix' => "</div>",
+      );
+    }
+    elseif ($info['type'] == HOSTING_QUEUE_TYPE_SPREAD) {
       $form[$queue]['frequency']['items'] = array(
         '#markup' => t('%count %items every', array(
           "%count" => $info['total_items'],
@@ -982,7 +1039,7 @@ function hosting_queues_configure_submit($form, &$form_state) {
     if ($form_state['values'][$queue]) {
       variable_set("hosting_queue_" . $queue . "_enabled", $form_state['values'][$queue]['enabled']);
       variable_set("hosting_queue_" . $queue . "_frequency", $form_state['values'][$queue]['frequency']['ticks'] * $form_state['values'][$queue]['frequency']['unit']);
-      if ($info['type'] == 'serial') {
+      if ($info['type'] == HOSTING_QUEUE_TYPE_SERIAL) {
         variable_set("hosting_queue_" . $queue . "_items", $form_state['values'][$queue]['frequency']['items']);
       }
     }
diff --git a/hosting.queues.inc b/hosting.queues.inc
index 7d7546d..79f54de 100644
--- a/hosting.queues.inc
+++ b/hosting.queues.inc
@@ -59,7 +59,7 @@ function hosting_get_queues($refresh = FALSE) {
   if (is_null($cache) || $refresh) {
     $cache = array();
     $defaults = array(
-      'type' => 'serial',
+      'type' => HOSTING_QUEUE_TYPE_SERIAL,
       'max_threads' => 6,
       'threshold' => '100',
       'min_threads' => 1,
@@ -70,7 +70,11 @@ function hosting_get_queues($refresh = FALSE) {
       'singular' => t('item'),
       'plural' => t('items'),
     );
-    $queues = module_invoke_all("hosting_queues");
+    $queues = module_invoke_all('hosting_queues');
+    if (!is_array($queues)) {
+      $queues = array();
+    }
+    drupal_alter('hosting_queues', $queues);
     foreach ($queues as $key => $queue) {
       $queue = array_merge($defaults, $queue);
 
@@ -84,7 +88,7 @@ function hosting_get_queues($refresh = FALSE) {
       );
       $queue = array_merge($queue, $configured);
 
-      if ($queue['type'] == 'batch') {
+      if ($queue['type'] == HOSTING_QUEUE_TYPE_BATCH) {
         $threads = $queue['total_items'] / $queue['threshold'];
         if ($threads <= $queue['min_threads']) {
           $threads = $queue['min_threads'];
@@ -96,6 +100,23 @@ function hosting_get_queues($refresh = FALSE) {
         $queue['calc_frequency'] = ceil($queue['frequency'] / $threads);
         $queue['calc_items'] = ceil($queue['total_items'] / $threads);
       }
+      elseif ($queue['type'] == HOSTING_QUEUE_TYPE_SPREAD) {
+        // If there are 0 items in the queue avoid a division by 0.
+        if ($queue['total_items'] > 0) {
+          // Process the queue as often as is needed to get through all the
+          // items once per frequency, but at most once a minute since the
+          // default dispatcher runs that quickly.
+          $queue['calc_frequency'] = max(60, $queue['frequency'] / $queue['total_items']);
+          // Compute the number of items to process per invocation. Usually this is will be 1.
+          $queue['calc_items'] = ceil($queue['calc_frequency'] / $queue['frequency'] * $queue['total_items']);
+        }
+        else {
+          // There are 0 items in the queue, process 0 tasks once a day anyway.
+          $queue['calc_frequency'] = 86400;
+          $queue['calc_items'] = 0;
+        }
+        $queue['running_items'] = 0;
+      }
       else {
         $queue['calc_frequency'] = $queue['frequency'];
         $queue['calc_items'] = $queue['items'];
@@ -104,6 +125,8 @@ function hosting_get_queues($refresh = FALSE) {
       $queue['last'] = variable_get('hosting_queue_' . $key . '_last_run', 0);
       $queues[$key] = $queue;
     }
+    // Allow altering the processed queue data.
+    drupal_alter('hosting_processed_queues', $queues);
     $cache = $queues;
   }
 
diff --git a/task_gc/hosting_task_gc.module b/task_gc/hosting_task_gc.module
index 4fb6273..a9b3fab 100644
--- a/task_gc/hosting_task_gc.module
+++ b/task_gc/hosting_task_gc.module
@@ -10,7 +10,7 @@ function hosting_task_gc_hosting_queues() {
   $queue['task_gc'] = array(
     'name' => t('Task GC'),
     'description' => t('Process the garbage collection of task logs.'),
-    'type' => 'batch',  # run queue sequentially. always with the same parameters.
+    'type' => HOSTING_QUEUE_TYPE_BATCH,  # run queue sequentially. always with the same parameters.
     'frequency' => strtotime("1 hour", 0),
     'items' => 20,
     'total_items' => $count,
