diff --git a/resources/sql/autopatches/20190215.daemons.01.dropdataid.php b/resources/sql/autopatches/20190215.daemons.01.dropdataid.php
new file mode 100644
index 0000000000..05cc4adfee
--- /dev/null
+++ b/resources/sql/autopatches/20190215.daemons.01.dropdataid.php
@@ -0,0 +1,21 @@
+<?php
+
+// See T6615. We're about to change the nullability on the "dataID" column,
+// but it may have a UNIQUE KEY on it. Make sure we get rid of this key first
+// so we don't run into trouble.
+
+// There's no "IF EXISTS" modifier for "ALTER TABLE" so run this as a PHP patch
+// instead of an SQL patch.
+
+$table = new PhabricatorWorkerActiveTask();
+$conn = $table->establishConnection('w');
+
+try {
+  queryfx(
+    $conn,
+    'ALTER TABLE %R DROP KEY %T',
+    $table,
+    'dataID');
+} catch (AphrontQueryException $ex) {
+  // Ignore.
+}
diff --git a/resources/sql/autopatches/20190215.daemons.02.nulldataid.sql b/resources/sql/autopatches/20190215.daemons.02.nulldataid.sql
new file mode 100644
index 0000000000..19be602efe
--- /dev/null
+++ b/resources/sql/autopatches/20190215.daemons.02.nulldataid.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {$NAMESPACE}_worker.worker_activetask
+  CHANGE dataID dataID INT UNSIGNED NOT NULL;
diff --git a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php
index ed1eeaea63..b6bd462df7 100644
--- a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php
+++ b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php
@@ -1,228 +1,214 @@
 <?php
 
 final class PhabricatorWorkerActiveTask extends PhabricatorWorkerTask {
 
   protected $failureTime;
 
   private $serverTime;
   private $localTime;
 
   protected function getConfiguration() {
     $parent = parent::getConfiguration();
 
     $config = array(
       self::CONFIG_IDS => self::IDS_COUNTER,
       self::CONFIG_TIMESTAMPS => false,
       self::CONFIG_KEY_SCHEMA => array(
-        'dataID' => array(
-          'columns' => array('dataID'),
-          'unique' => true,
-        ),
         'taskClass' => array(
           'columns' => array('taskClass'),
         ),
         'leaseExpires' => array(
           'columns' => array('leaseExpires'),
         ),
-        'leaseOwner' => array(
-          'columns' => array('leaseOwner(16)'),
-        ),
         'key_failuretime' => array(
           'columns' => array('failureTime'),
         ),
-        'leaseOwner_2' => array(
+        'key_owner' => array(
           'columns' => array('leaseOwner', 'priority', 'id'),
         ),
       ) + $parent[self::CONFIG_KEY_SCHEMA],
     );
 
-    $config[self::CONFIG_COLUMN_SCHEMA] = array(
-      // T6203/NULLABILITY
-      // This isn't nullable in the archive table, so at a minimum these
-      // should be the same.
-      'dataID' => 'uint32?',
-    ) + $parent[self::CONFIG_COLUMN_SCHEMA];
-
     return $config + $parent;
   }
 
   public function setServerTime($server_time) {
     $this->serverTime = $server_time;
     $this->localTime = time();
     return $this;
   }
 
   public function setLeaseDuration($lease_duration) {
     $this->checkLease();
     $server_lease_expires = $this->serverTime + $lease_duration;
     $this->setLeaseExpires($server_lease_expires);
 
     // NOTE: This is primarily to allow unit tests to set negative lease
     // durations so they don't have to wait around for leases to expire. We
     // check that the lease is valid above.
     return $this->forceSaveWithoutLease();
   }
 
   public function save() {
     $this->checkLease();
     return $this->forceSaveWithoutLease();
   }
 
   public function forceSaveWithoutLease() {
     $is_new = !$this->getID();
     if ($is_new) {
       $this->failureCount = 0;
     }
 
-    if ($is_new && ($this->getData() !== null)) {
+    if ($is_new) {
       $data = new PhabricatorWorkerTaskData();
       $data->setData($this->getData());
       $data->save();
 
       $this->setDataID($data->getID());
     }
 
     return parent::save();
   }
 
   protected function checkLease() {
     $owner = $this->leaseOwner;
 
     if (!$owner) {
       return;
     }
 
     if ($owner == PhabricatorWorker::YIELD_OWNER) {
       return;
     }
 
     $current_server_time = $this->serverTime + (time() - $this->localTime);
     if ($current_server_time >= $this->leaseExpires) {
       throw new Exception(
         pht(
           'Trying to update Task %d (%s) after lease expiration!',
           $this->getID(),
           $this->getTaskClass()));
     }
   }
 
   public function delete() {
     throw new Exception(
       pht(
         'Active tasks can not be deleted directly. '.
         'Use %s to move tasks to the archive.',
         'archiveTask()'));
   }
 
   public function archiveTask($result, $duration) {
     if ($this->getID() === null) {
       throw new Exception(
         pht("Attempting to archive a task which hasn't been saved!"));
     }
 
     $this->checkLease();
 
     $archive = id(new PhabricatorWorkerArchiveTask())
       ->setID($this->getID())
       ->setTaskClass($this->getTaskClass())
       ->setLeaseOwner($this->getLeaseOwner())
       ->setLeaseExpires($this->getLeaseExpires())
       ->setFailureCount($this->getFailureCount())
       ->setDataID($this->getDataID())
       ->setPriority($this->getPriority())
       ->setObjectPHID($this->getObjectPHID())
       ->setResult($result)
       ->setDuration($duration);
 
     // NOTE: This deletes the active task (this object)!
     $archive->save();
 
     return $archive;
   }
 
   public function executeTask() {
     // We do this outside of the try .. catch because we don't have permission
     // to release the lease otherwise.
     $this->checkLease();
 
     $did_succeed = false;
     $worker = null;
     try {
       $worker = $this->getWorkerInstance();
       $worker->setCurrentWorkerTask($this);
 
       $maximum_failures = $worker->getMaximumRetryCount();
       if ($maximum_failures !== null) {
         if ($this->getFailureCount() > $maximum_failures) {
           throw new PhabricatorWorkerPermanentFailureException(
             pht(
               'Task %d has exceeded the maximum number of failures (%d).',
               $this->getID(),
               $maximum_failures));
         }
       }
 
       $lease = $worker->getRequiredLeaseTime();
       if ($lease !== null) {
         $this->setLeaseDuration($lease);
       }
 
       $t_start = microtime(true);
         $worker->executeTask();
       $duration = phutil_microseconds_since($t_start);
 
       $result = $this->archiveTask(
         PhabricatorWorkerArchiveTask::RESULT_SUCCESS,
         $duration);
       $did_succeed = true;
     } catch (PhabricatorWorkerPermanentFailureException $ex) {
       $result = $this->archiveTask(
         PhabricatorWorkerArchiveTask::RESULT_FAILURE,
         0);
       $result->setExecutionException($ex);
     } catch (PhabricatorWorkerYieldException $ex) {
       $this->setExecutionException($ex);
 
       $this->setLeaseOwner(PhabricatorWorker::YIELD_OWNER);
 
       $retry = $ex->getDuration();
       $retry = max($retry, 5);
 
       // NOTE: As a side effect, this saves the object.
       $this->setLeaseDuration($retry);
 
       $result = $this;
     } catch (Exception $ex) {
       $this->setExecutionException($ex);
       $this->setFailureCount($this->getFailureCount() + 1);
       $this->setFailureTime(time());
 
       $retry = null;
       if ($worker) {
         $retry = $worker->getWaitBeforeRetry($this);
       }
 
       $retry = coalesce(
         $retry,
         PhabricatorWorkerLeaseQuery::getDefaultWaitBeforeRetry());
 
       // NOTE: As a side effect, this saves the object.
       $this->setLeaseDuration($retry);
 
       $result = $this;
     }
 
     // NOTE: If this throws, we don't want it to cause the task to fail again,
     // so execute it out here and just let the exception escape.
     if ($did_succeed) {
       // Default the new task priority to our own priority.
       $defaults = array(
         'priority' => (int)$this->getPriority(),
       );
       $worker->flushTaskQueue($defaults);
     }
 
     return $result;
   }
 
 }
diff --git a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php
index fe1164e532..0062d07a84 100644
--- a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php
+++ b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php
@@ -1,100 +1,97 @@
 <?php
 
 final class PhabricatorWorkerArchiveTask extends PhabricatorWorkerTask {
 
   const RESULT_SUCCESS    = 0;
   const RESULT_FAILURE    = 1;
   const RESULT_CANCELLED  = 2;
 
   protected $duration;
   protected $result;
 
   protected function getConfiguration() {
     $parent = parent::getConfiguration();
 
     $config = array(
       // We manage the IDs in this table; they are allocated in the ActiveTask
       // table and moved here without alteration.
       self::CONFIG_IDS => self::IDS_MANUAL,
     ) + $parent;
 
 
     $config[self::CONFIG_COLUMN_SCHEMA] = array(
       'result' => 'uint32',
       'duration' => 'uint64',
     ) + $config[self::CONFIG_COLUMN_SCHEMA];
 
     $config[self::CONFIG_KEY_SCHEMA] = array(
       'dateCreated' => array(
         'columns' => array('dateCreated'),
       ),
-      'leaseOwner' => array(
-        'columns' => array('leaseOwner', 'priority', 'id'),
-      ),
       'key_modified' => array(
         'columns' => array('dateModified'),
       ),
     ) + $parent[self::CONFIG_KEY_SCHEMA];
 
     return $config;
   }
 
   public function save() {
     if ($this->getID() === null) {
       throw new Exception(pht('Trying to archive a task with no ID.'));
     }
 
     $other = new PhabricatorWorkerActiveTask();
     $conn_w = $this->establishConnection('w');
 
     $this->openTransaction();
       queryfx(
         $conn_w,
         'DELETE FROM %T WHERE id = %d',
         $other->getTableName(),
         $this->getID());
       $result = parent::insert();
     $this->saveTransaction();
 
     return $result;
   }
 
   public function delete() {
     $this->openTransaction();
       if ($this->getDataID()) {
         $conn_w = $this->establishConnection('w');
         $data_table = new PhabricatorWorkerTaskData();
 
         queryfx(
           $conn_w,
           'DELETE FROM %T WHERE id = %d',
           $data_table->getTableName(),
           $this->getDataID());
       }
 
       $result = parent::delete();
     $this->saveTransaction();
     return $result;
   }
 
   public function unarchiveTask() {
     $this->openTransaction();
       $active = id(new PhabricatorWorkerActiveTask())
         ->setID($this->getID())
         ->setTaskClass($this->getTaskClass())
         ->setLeaseOwner(null)
         ->setLeaseExpires(0)
         ->setFailureCount(0)
         ->setDataID($this->getDataID())
         ->setPriority($this->getPriority())
         ->setObjectPHID($this->getObjectPHID())
         ->insert();
 
       $this->setDataID(null);
       $this->delete();
     $this->saveTransaction();
 
     return $active;
   }
 
 }