diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2373,6 +2373,7 @@
     'PhabricatorImageMacroRemarkupRule' => 'applications/macro/markup/PhabricatorImageMacroRemarkupRule.php',
     'PhabricatorImageTransformer' => 'applications/files/PhabricatorImageTransformer.php',
     'PhabricatorImagemagickSetupCheck' => 'applications/config/check/PhabricatorImagemagickSetupCheck.php',
+    'PhabricatorIndexEngine' => 'applications/search/index/PhabricatorIndexEngine.php',
     'PhabricatorInfrastructureTestCase' => '__tests__/PhabricatorInfrastructureTestCase.php',
     'PhabricatorInlineCommentController' => 'infrastructure/diff/PhabricatorInlineCommentController.php',
     'PhabricatorInlineCommentInterface' => 'infrastructure/diff/interface/PhabricatorInlineCommentInterface.php',
@@ -3030,7 +3031,6 @@
     'PhabricatorSearchEngineTestCase' => 'applications/search/engine/__tests__/PhabricatorSearchEngineTestCase.php',
     'PhabricatorSearchField' => 'applications/search/field/PhabricatorSearchField.php',
     'PhabricatorSearchHovercardController' => 'applications/search/controller/PhabricatorSearchHovercardController.php',
-    'PhabricatorSearchIndexer' => 'applications/search/index/PhabricatorSearchIndexer.php',
     'PhabricatorSearchManagementIndexWorkflow' => 'applications/search/management/PhabricatorSearchManagementIndexWorkflow.php',
     'PhabricatorSearchManagementInitWorkflow' => 'applications/search/management/PhabricatorSearchManagementInitWorkflow.php',
     'PhabricatorSearchManagementWorkflow' => 'applications/search/management/PhabricatorSearchManagementWorkflow.php',
@@ -6593,6 +6593,7 @@
     'PhabricatorImageMacroRemarkupRule' => 'PhutilRemarkupRule',
     'PhabricatorImageTransformer' => 'Phobject',
     'PhabricatorImagemagickSetupCheck' => 'PhabricatorSetupCheck',
+    'PhabricatorIndexEngine' => 'Phobject',
     'PhabricatorInfrastructureTestCase' => 'PhabricatorTestCase',
     'PhabricatorInlineCommentController' => 'PhabricatorController',
     'PhabricatorInlineCommentInterface' => 'PhabricatorMarkupInterface',
@@ -7374,7 +7375,6 @@
     'PhabricatorSearchEngineTestCase' => 'PhabricatorTestCase',
     'PhabricatorSearchField' => 'Phobject',
     'PhabricatorSearchHovercardController' => 'PhabricatorSearchBaseController',
-    'PhabricatorSearchIndexer' => 'Phobject',
     'PhabricatorSearchManagementIndexWorkflow' => 'PhabricatorSearchManagementWorkflow',
     'PhabricatorSearchManagementInitWorkflow' => 'PhabricatorSearchManagementWorkflow',
     'PhabricatorSearchManagementWorkflow' => 'PhabricatorManagementWorkflow',
diff --git a/src/applications/diviner/publisher/DivinerLivePublisher.php b/src/applications/diviner/publisher/DivinerLivePublisher.php
--- a/src/applications/diviner/publisher/DivinerLivePublisher.php
+++ b/src/applications/diviner/publisher/DivinerLivePublisher.php
@@ -40,8 +40,7 @@
       $conn_w->saveTransaction();
       $this->book = $book;
 
-      id(new PhabricatorSearchIndexer())
-        ->queueDocumentForIndexing($book->getPHID());
+      PhabricatorSearchWorker::queueDocumentForIndexing($book->getPHID());
     }
 
     return $this->book;
@@ -147,8 +146,7 @@
 
       $symbol->save();
 
-      id(new PhabricatorSearchIndexer())
-        ->queueDocumentForIndexing($symbol->getPHID());
+      PhabricatorSearchWorker::queueDocumentForIndexing($symbol->getPHID());
 
       // TODO: We probably need a finer-grained sense of what "documentable"
       // atoms are. Neither files nor methods are currently considered
diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php
--- a/src/applications/people/storage/PhabricatorUser.php
+++ b/src/applications/people/storage/PhabricatorUser.php
@@ -273,8 +273,7 @@
 
     $this->updateNameTokens();
 
-    id(new PhabricatorSearchIndexer())
-      ->queueDocumentForIndexing($this->getPHID());
+    PhabricatorSearchWorker::queueDocumentForIndexing($this->getPHID());
 
     return $result;
   }
diff --git a/src/applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php b/src/applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php
--- a/src/applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php
+++ b/src/applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php
@@ -93,8 +93,7 @@
     $commit->writeImportStatusFlag(
       PhabricatorRepositoryCommit::IMPORTED_CHANGE);
 
-    id(new PhabricatorSearchIndexer())
-      ->queueDocumentForIndexing($commit->getPHID());
+    PhabricatorSearchWorker::queueDocumentForIndexing($commit->getPHID());
 
     if ($this->shouldQueueFollowupTasks()) {
       $this->queueTask(
diff --git a/src/applications/search/index/PhabricatorSearchIndexer.php b/src/applications/search/index/PhabricatorIndexEngine.php
rename from src/applications/search/index/PhabricatorSearchIndexer.php
rename to src/applications/search/index/PhabricatorIndexEngine.php
--- a/src/applications/search/index/PhabricatorSearchIndexer.php
+++ b/src/applications/search/index/PhabricatorIndexEngine.php
@@ -1,18 +1,6 @@
 <?php
 
-final class PhabricatorSearchIndexer extends Phobject {
-
-  public function queueDocumentForIndexing($phid, $context = null) {
-    PhabricatorWorker::scheduleTask(
-      'PhabricatorSearchWorker',
-      array(
-        'documentPHID' => $phid,
-        'context' => $context,
-      ),
-      array(
-        'priority' => PhabricatorWorker::PRIORITY_IMPORT,
-      ));
-  }
+final class PhabricatorIndexEngine extends Phobject {
 
   public function indexDocumentByPHID($phid, $context) {
     $indexers = id(new PhutilClassMapQuery())
diff --git a/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php b/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php
--- a/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php
+++ b/src/applications/search/management/PhabricatorSearchManagementIndexWorkflow.php
@@ -94,10 +94,9 @@
       ->setTotal(count($phids));
 
     $any_success = false;
-    $indexer = new PhabricatorSearchIndexer();
     foreach ($phids as $phid) {
       try {
-        $indexer->queueDocumentForIndexing($phid);
+        PhabricatorSearchWorker::queueDocumentForIndexing($phid);
         $any_success = true;
       } catch (Exception $ex) {
         phlog($ex);
diff --git a/src/applications/search/worker/PhabricatorSearchWorker.php b/src/applications/search/worker/PhabricatorSearchWorker.php
--- a/src/applications/search/worker/PhabricatorSearchWorker.php
+++ b/src/applications/search/worker/PhabricatorSearchWorker.php
@@ -2,22 +2,68 @@
 
 final class PhabricatorSearchWorker extends PhabricatorWorker {
 
+  public static function queueDocumentForIndexing($phid, $context = null) {
+    parent::scheduleTask(
+      __CLASS__,
+      array(
+        'documentPHID' => $phid,
+        'context' => $context,
+      ),
+      array(
+        'priority' => parent::PRIORITY_IMPORT,
+      ));
+  }
+
   protected function doWork() {
     $data = $this->getTaskData();
-
-    $phid = idx($data, 'documentPHID');
+    $object_phid = idx($data, 'documentPHID');
     $context = idx($data, 'context');
 
+    $engine = new PhabricatorIndexEngine();
+
+    $key = "index.{$object_phid}";
+    $lock = PhabricatorGlobalLock::newLock($key);
+
+    $lock->lock(1);
+
     try {
-      id(new PhabricatorSearchIndexer())
-        ->indexDocumentByPHID($phid, $context);
+      $object = $this->loadObjectForIndexing($object_phid);
+
+      $engine->indexDocumentByPHID($object->getPHID(), $context);
+
     } catch (Exception $ex) {
+      $lock->unlock();
+
+      if (!($ex instanceof PhabricatorWorkerPermanentFailureException)) {
+        $ex = new PhabricatorWorkerPermanentFailureException(
+          pht(
+            'Failed to update search index for document "%s": %s',
+            $object_phid,
+            $ex->getMessage()));
+      }
+
+      throw $ex;
+    }
+
+    $lock->unlock();
+  }
+
+  private function loadObjectForIndexing($phid) {
+    $viewer = PhabricatorUser::getOmnipotentUser();
+
+    $object = id(new PhabricatorObjectQuery())
+      ->setViewer($viewer)
+      ->withPHIDs(array($phid))
+      ->executeOne();
+
+    if (!$object) {
       throw new PhabricatorWorkerPermanentFailureException(
         pht(
-          'Failed to update search index for document "%s": %s',
-          $phid,
-          $ex->getMessage()));
+          'Unable to load object "%s" to rebuild indexes.',
+          $phid));
     }
+
+    return $object;
   }
 
 }
diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
--- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
+++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
@@ -1093,10 +1093,9 @@
     }
 
     if ($this->supportsSearch()) {
-      id(new PhabricatorSearchIndexer())
-        ->queueDocumentForIndexing(
-          $object->getPHID(),
-          $this->getSearchContextParameter($object, $xactions));
+      PhabricatorSearchWorker::queueDocumentForIndexing(
+        $object->getPHID(),
+        $this->getSearchContextParameter($object, $xactions));
     }
 
     if ($this->shouldPublishFeedStory($object, $xactions)) {