 drafty.module | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 drafty.test   | 49 ++++++++++++++++++++++++++++++++++
 2 files changed, 130 insertions(+), 5 deletions(-)

diff --git a/drafty.module b/drafty.module
index db34632..34e145c 100644
--- a/drafty.module
+++ b/drafty.module
@@ -81,6 +81,53 @@ function drafty_field_attach_load($entity_type, $entities, $age, $options) {
 }
 
 /**
+ * Callback function to delete a single temporary-draft revision.
+ * Could be called either from a batch job or from a cron-queue.
+ */
+function drafty_queue_delete_revision($drafty_queue_item, &$context = NULL) {
+  try {
+    entity_revision_delete($drafty_queue_item['entity_type'], $drafty_queue_item['revision_id']);
+    if (!empty($context) && isset($context['results'])){
+      // Document the successful batch operation for the batch-finished function to use.
+      $context['results'][] = $drafty_queue_item;
+    }
+  }
+  catch(Exception $ex){
+    // Log the problem
+    $message = 'An error occurred while deleting temporary revision: @args. Exception details: @error';
+    $args = array(
+      '@args' => print_r($drafty_queue_item, TRUE),
+      '@error' => print_r($ex),
+    );
+    watchdog('drafty', $message, $args, WATCHDOG_ERROR);
+    throw $ex;  // Batch API will pass $success = FALSE.
+  }
+}
+
+
+/**
+ * Implements hook_cron_queue_info().
+ */
+function drafty_cron_queue_info() {
+  $queues['drafty_revision_delete'] = array(
+    'worker callback' => 'drafty_queue_delete_revision',
+    'time' => 60,
+  );
+  return $queues;
+}
+
+/**
+ * Batch completion callback for when draft-deletes happen in a batch job.
+ * $results contains info about successfully deleted revisions, and
+ * exception objects for revision-delete options that caused problems.
+ * $operations contains the operations that remained unprocessed.
+ */
+function drafty_delete_batch_finished($success, $results, $operations) {
+  // TODO: Display a message about temporary-revision-cleanup here?
+  // Note that logging of failed deletes is handled by the operation callback.
+}
+
+/**
  * Factory function for the DraftyTracker class.
  */
 function drafty() {
@@ -241,20 +288,49 @@ class Drafty {
    * Publish revisions previously set with setRevisionToBePublished().
    */
   public function restorePublishedRevisions() {
+    $delete_old_revisions = variable_get('drafty_delete_old_revisions', FALSE);
+    $delete_with_cron = variable_get('drafty_delete_with_cron', TRUE);
+    $queue = null;
+    $operations = array();
     foreach ($this->revisionsToPublish as $type => $value) {
       foreach ($value as $id => $vid) {
         unset($this->revisionsToPublish[$type][$id]);
         $this->publishRevision($type, $id, $vid);
         // Now that the revision is deleted, there are two identical copies of
         // the revision in the system. The original 'draft' revision and the
-        // newly saved published revision. Delete the draft revision now since
-        // it's not needed.
-        // @todo: make this configurable?
+        // newly saved published revision. 
+        if ($delete_old_revisions) {
+          // Deletion must be done on a different request thread, or any other
+          // hooks called for the revision-to-be-deleted will fail.
+          $drafty_queue_item = array(
+            'entity_type' => $type,
+            'entity_id' => $id,
+            'revision_id' => $vid,
+          );
+          if ($delete_with_cron){
+            if (empty($queue)){
+              $queue = DrupalQueue::get('drafty_revision_delete');
+            }
+            $queue->createItem($drafty_queue_item);
+          }
+          else {
+            $operations[] = array(
+              'drafty_queue_delete_revision', 
+              array(
+                $drafty_queue_item)
+              );
+          }
+        }
         // @todo: when restoring a published revision, should the revision
         // timestamp be set to the old value?
-        // @todo: move this to a queue since the deletion doesn't strictly have
-        // to happen inline.
       }
     }
+    if (!empty($operations)){
+      $batch = array(
+        'operations' => $operations,
+        'finished' => 'drafty_delete_batch_finished',
+      );
+      batch_set($batch);
+    }
   }
 }
diff --git a/drafty.test b/drafty.test
index 6c22f59..7ae5ec8 100644
--- a/drafty.test
+++ b/drafty.test
@@ -81,6 +81,55 @@ class DraftyTestCase extends DraftyWebTestCase {
     $this->assertEqual($node->title, 'Title B');
     $this->assertNotEqual($node->vid, $draft_vid);
   }
+
+  /**
+   * Create a published node. Then create a draft and check if the previous
+   * published revision was cleaned by cron.
+   */
+  function testDraftyRevisionCleanup() {
+    $node = new stdClass();
+    $node->title = 'Title A';
+    $node->type = 'article';
+    $node->status = 1;
+    $this->setRevision($node);
+    node_save($node);
+
+    // Save the vid for later comparison.
+    $first_published_vid = $node->vid;
+
+    // Save a new draft.
+    $node = node_load($node->nid);
+    $node->title = 'Title B';
+    $this->setRevision($node);
+    $node->is_draft_revision = TRUE;
+    node_save($node);
+
+    $node = node_load($node->nid);
+    $second_published_vid = $node->vid;
+
+    // Run cron
+    $this->drupalGet($GLOBALS['base_url'] . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => variable_get('cron_key', 'drupal'))));
+
+    // Check that the $first_published_vid is still present
+    $nodes = node_load_multiple(array($node->nid), array('vid' => $first_published_vid));
+    $this->assertTrue(!empty($nodes), 'Old published revision is still present.');
+
+    // Configure drafty to clean old published revisions
+    variable_set('drafty_delete_old_revisions', TRUE);
+
+    // Create new draft revision
+    $node->title = 'Title C';
+    $this->setRevision($node);
+    $node->is_draft_revision = TRUE;
+    node_save($node);
+
+    // Run cron
+    $this->drupalGet($GLOBALS['base_url'] . '/cron.php', array('external' => TRUE, 'query' => array('cron_key' => variable_get('cron_key', 'drupal'))));
+
+    // Confirm the the second published revision has been deleted.
+    $nodes = node_load_multiple(array($node->nid), array('vid' => $second_published_vid));
+    $this->assertTrue(empty($nodes), 'Old published revision has been deleted.');
+  }
 }
 
 /**
