diff --git a/src/applications/drydock/storage/DrydockLease.php b/src/applications/drydock/storage/DrydockLease.php
--- a/src/applications/drydock/storage/DrydockLease.php
+++ b/src/applications/drydock/storage/DrydockLease.php
@@ -334,10 +334,15 @@
       ),
       array(
         'objectPHID' => $this->getPHID(),
-        'delayUntil' => $epoch,
+        'delayUntil' => ($epoch ? (int)$epoch : null),
       ));
   }
 
+  public function setAwakenTaskIDs(array $ids) {
+    $this->setAttribute('internal.awakenTaskIDs', $ids);
+    return $this;
+  }
+
   private function didActivate() {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $need_update = false;
@@ -359,6 +364,11 @@
     if ($expires) {
       $this->scheduleUpdate($expires);
     }
+
+    $awaken_ids = $this->getAttribute('internal.awakenTaskIDs');
+    if (is_array($awaken_ids) && $awaken_ids) {
+      PhabricatorWorker::awakenTaskIDs($awaken_ids);
+    }
   }
 
 
diff --git a/src/applications/drydock/storage/DrydockResource.php b/src/applications/drydock/storage/DrydockResource.php
--- a/src/applications/drydock/storage/DrydockResource.php
+++ b/src/applications/drydock/storage/DrydockResource.php
@@ -218,7 +218,7 @@
       ),
       array(
         'objectPHID' => $this->getPHID(),
-        'delayUntil' => $epoch,
+        'delayUntil' => ($epoch ? (int)$epoch : null),
       ));
   }
 
diff --git a/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php
--- a/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php
+++ b/src/applications/harbormaster/step/HarbormasterBuildStepImplementation.php
@@ -6,6 +6,16 @@
 abstract class HarbormasterBuildStepImplementation extends Phobject {
 
   private $settings;
+  private $currentWorkerTaskID;
+
+  public function setCurrentWorkerTaskID($id) {
+    $this->currentWorkerTaskID = $id;
+    return $this;
+  }
+
+  public function getCurrentWorkerTaskID() {
+    return $this->currentWorkerTaskID;
+  }
 
   public static function getImplementations() {
     return id(new PhutilClassMapQuery())
diff --git a/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
--- a/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
+++ b/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php
@@ -54,6 +54,11 @@
         ->setAttribute('repositoryPHID', $repository_phid)
         ->setAttribute('commit', $commit);
 
+      $task_id = $this->getCurrentWorkerTaskID();
+      if ($task_id) {
+        $lease->setAwakenTaskIDs(array($task_id));
+      }
+
       $lease->queueForActivation();
 
       $build_target
diff --git a/src/applications/harbormaster/worker/HarbormasterTargetWorker.php b/src/applications/harbormaster/worker/HarbormasterTargetWorker.php
--- a/src/applications/harbormaster/worker/HarbormasterTargetWorker.php
+++ b/src/applications/harbormaster/worker/HarbormasterTargetWorker.php
@@ -59,6 +59,7 @@
       }
 
       $implementation = $target->getImplementation();
+      $implementation->setCurrentWorkerTaskID($this->getCurrentWorkerTaskID());
       $implementation->execute($build, $target);
 
       $next_status = HarbormasterBuildTarget::STATUS_PASSED;
diff --git a/src/infrastructure/daemon/workers/PhabricatorWorker.php b/src/infrastructure/daemon/workers/PhabricatorWorker.php
--- a/src/infrastructure/daemon/workers/PhabricatorWorker.php
+++ b/src/infrastructure/daemon/workers/PhabricatorWorker.php
@@ -8,6 +8,7 @@
   private $data;
   private static $runAllTasksInProcess = false;
   private $queuedTasks = array();
+  private $currentWorkerTask;
 
   // NOTE: Lower priority numbers execute first. The priority numbers have to
   // have the same ordering that IDs do (lowest first) so MySQL can use a
@@ -18,6 +19,10 @@
   const PRIORITY_BULK    = 3000;
   const PRIORITY_IMPORT  = 4000;
 
+  /**
+   * Special owner indicating that the task has yielded.
+   */
+  const YIELD_OWNER = '(yield)';
 
 /* -(  Configuring Retries and Failures  )----------------------------------- */
 
@@ -77,6 +82,23 @@
     return null;
   }
 
+  public function setCurrentWorkerTask(PhabricatorWorkerTask $task) {
+    $this->currentWorkerTask = $task;
+    return $this;
+  }
+
+  public function getCurrentWorkerTask() {
+    return $this->currentWorkerTask;
+  }
+
+  public function getCurrentWorkerTaskID() {
+    $task = $this->getCurrentWorkerTask();
+    if (!$task) {
+      return null;
+    }
+    return $task->getID();
+  }
+
   abstract protected function doWork();
 
   final public function __construct($data) {
@@ -105,6 +127,14 @@
     $data,
     $options = array()) {
 
+    PhutilTypeSpec::checkMap(
+      $options,
+      array(
+        'priority' => 'optional int|null',
+        'objectPHID' => 'optional string|null',
+        'delayUntil' => 'optional int|null',
+      ));
+
     $priority = idx($options, 'priority');
     if ($priority === null) {
       $priority = self::PRIORITY_DEFAULT;
@@ -208,4 +238,49 @@
     return $this->queuedTasks;
   }
 
+
+  /**
+   * Awaken tasks that have yielded.
+   *
+   * Reschedules the specified tasks if they are currently queued in a yielded,
+   * unleased, unretried state so they'll execute sooner. This can let the
+   * queue avoid unnecessary waits.
+   *
+   * This method does not provide any assurances about when these tasks will
+   * execute, or even guarantee that it will have any effect at all.
+   *
+   * @param list<id> List of task IDs to try to awaken.
+   * @return void
+   */
+  final public static function awakenTaskIDs(array $ids) {
+    if (!$ids) {
+      return;
+    }
+
+    $table = new PhabricatorWorkerActiveTask();
+    $conn_w = $table->establishConnection('w');
+
+    // NOTE: At least for now, we're keeping these tasks yielded, just
+    // pretending that they threw a shorter yield than they really did.
+
+    // Overlap the windows here to handle minor client/server time differences
+    // and because it's likely correct to push these tasks to the head of their
+    // respective priorities. There is a good chance they are ready to execute.
+    $window = phutil_units('1 hour in seconds');
+    $epoch_ago = (PhabricatorTime::getNow() - $window);
+
+    queryfx(
+      $conn_w,
+      'UPDATE %T SET leaseExpires = %d
+        WHERE id IN (%Ld)
+          AND leaseOwner = %s
+          AND leaseExpires > %d
+          AND failureCount = 0',
+      $table->getTableName(),
+      $epoch_ago,
+      $ids,
+      self::YIELD_OWNER,
+      $epoch_ago);
+  }
+
 }
diff --git a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php
--- a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php
+++ b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php
@@ -141,6 +141,7 @@
     $worker = null;
     try {
       $worker = $this->getWorkerInstance();
+      $worker->setCurrentWorkerTask($this);
 
       $maximum_failures = $worker->getMaximumRetryCount();
       if ($maximum_failures !== null) {
@@ -175,6 +176,8 @@
     } catch (PhabricatorWorkerYieldException $ex) {
       $this->setExecutionException($ex);
 
+      $this->setLeaseOwner(PhabricatorWorker::YIELD_OWNER);
+
       $retry = $ex->getDuration();
       $retry = max($retry, 5);