You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aurora.apache.org by ma...@apache.org on 2014/10/17 18:29:13 UTC

git commit: Deprecating SANDBOX_DELETED task state.

Repository: incubator-aurora
Updated Branches:
  refs/heads/master f601d7b33 -> ffa126d68


Deprecating SANDBOX_DELETED task state.

Bugs closed: AURORA-751

Reviewed at https://reviews.apache.org/r/26664/


Project: http://git-wip-us.apache.org/repos/asf/incubator-aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-aurora/commit/ffa126d6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-aurora/tree/ffa126d6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-aurora/diff/ffa126d6

Branch: refs/heads/master
Commit: ffa126d68f821154b95e1da71724526dcacb6ac0
Parents: f601d7b
Author: Maxim Khutornenko <ma...@apache.org>
Authored: Fri Oct 17 09:28:57 2014 -0700
Committer: Maxim Khutornenko <ma...@apache.org>
Committed: Fri Oct 17 09:28:57 2014 -0700

----------------------------------------------------------------------
 .../scheduler/async/GcExecutorLauncher.java     |  8 +-
 .../org/apache/aurora/scheduler/base/Jobs.java  | 14 +--
 .../aurora/scheduler/sla/SlaAlgorithm.java      |  1 -
 .../scheduler/state/TaskStateMachine.java       | 33 +-------
 .../scheduler/storage/StorageBackfill.java      | 16 +++-
 .../apache/aurora/executor/gc_executor.py       |  3 +
 .../scheduler/assets/js/controllers.js          |  9 +-
 .../resources/scheduler/assets/js/filters.js    |  3 +-
 .../thrift/org/apache/aurora/gen/api.thrift     |  1 +
 .../aurora/scheduler/app/SchedulerIT.java       |  1 -
 .../scheduler/async/GcExecutorLauncherTest.java | 19 -----
 .../scheduler/async/TaskHistoryPrunerTest.java  |  5 +-
 .../apache/aurora/scheduler/base/JobsTest.java  | 22 +++--
 .../aurora/scheduler/sla/SlaAlgorithmTest.java  | 10 ---
 .../scheduler/state/StateManagerImplTest.java   | 28 +-----
 .../scheduler/state/TaskStateMachineTest.java   | 89 +-------------------
 .../scheduler/storage/StorageBackfillTest.java  | 30 +++++++
 17 files changed, 76 insertions(+), 216 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/main/java/org/apache/aurora/scheduler/async/GcExecutorLauncher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/async/GcExecutorLauncher.java b/src/main/java/org/apache/aurora/scheduler/async/GcExecutorLauncher.java
index dce88d7..feb70a9 100644
--- a/src/main/java/org/apache/aurora/scheduler/async/GcExecutorLauncher.java
+++ b/src/main/java/org/apache/aurora/scheduler/async/GcExecutorLauncher.java
@@ -25,7 +25,6 @@ import javax.inject.Inject;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
-import com.google.common.base.Predicates;
 import com.google.common.base.Supplier;
 import com.google.common.base.Throwables;
 import com.google.common.collect.Maps;
@@ -41,7 +40,6 @@ import com.twitter.common.util.Random;
 import org.apache.aurora.Protobufs;
 import org.apache.aurora.codec.ThriftBinaryCodec;
 import org.apache.aurora.codec.ThriftBinaryCodec.CodingException;
-import org.apache.aurora.gen.ScheduleStatus;
 import org.apache.aurora.gen.comm.AdjustRetainedTasks;
 import org.apache.aurora.scheduler.Driver;
 import org.apache.aurora.scheduler.TaskLauncher;
@@ -184,16 +182,14 @@ public class GcExecutorLauncher implements TaskLauncher {
     Set<IScheduledTask> tasksOnHost =
         Storage.Util.weaklyConsistentFetchTasks(storage, Query.slaveScoped(hostName));
 
-    Map<String, ScheduleStatus> tasks = Maps.filterValues(
-        Maps.transformValues(Tasks.mapById(tasksOnHost), Tasks.GET_STATUS),
-        Predicates.not(Predicates.equalTo(ScheduleStatus.SANDBOX_DELETED)));
     tasksCreated.incrementAndGet();
     return makeGcTask(
         hostName,
         slaveId,
         settings.getGcExecutorPath().get(),
         uuidGenerator.get(),
-        new AdjustRetainedTasks().setRetainedTasks(tasks));
+        new AdjustRetainedTasks().setRetainedTasks(
+            Maps.transformValues(Tasks.mapById(tasksOnHost), Tasks.GET_STATUS)));
   }
 
   private boolean sufficientResources(Offer offer) {

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/main/java/org/apache/aurora/scheduler/base/Jobs.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/base/Jobs.java b/src/main/java/org/apache/aurora/scheduler/base/Jobs.java
index 9ba83fa..49e5b2c 100644
--- a/src/main/java/org/apache/aurora/scheduler/base/Jobs.java
+++ b/src/main/java/org/apache/aurora/scheduler/base/Jobs.java
@@ -17,7 +17,6 @@ import org.apache.aurora.gen.JobStats;
 import org.apache.aurora.gen.ScheduleStatus;
 import org.apache.aurora.scheduler.storage.entities.IJobStats;
 import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
-import org.apache.aurora.scheduler.storage.entities.ITaskEvent;
 
 /**
  * Convenience methods related to jobs.
@@ -28,10 +27,6 @@ public final class Jobs {
     // Utility class.
   }
 
-  private static ITaskEvent getSecondToLatestEvent(IScheduledTask task) {
-    return task.getTaskEvents().get(task.getTaskEvents().size() - 2);
-  }
-
   /**
    * For a given collection of tasks compute statistics based on the state of the task.
    *
@@ -41,19 +36,12 @@ public final class Jobs {
   public static IJobStats getJobStats(Iterable<IScheduledTask> tasks) {
     JobStats stats = new JobStats();
     for (IScheduledTask task : tasks) {
-      ScheduleStatus status = task.getStatus();
-      if (status == ScheduleStatus.SANDBOX_DELETED) {
-        // SANDBOX_DELETED must be preceded by the real terminal state.
-        updateStats(stats, getSecondToLatestEvent(task).getStatus());
-      } else {
-        updateStats(stats, status);
-      }
+      updateStats(stats, task.getStatus());
     }
     return IJobStats.build(stats);
   }
 
   private static void updateStats(JobStats stats, ScheduleStatus status) {
-    // The SANDBOX_DELETED state is processed separately as it hides the real termination reason.
     switch (status) {
       case INIT:
       case PENDING:

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/main/java/org/apache/aurora/scheduler/sla/SlaAlgorithm.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/sla/SlaAlgorithm.java b/src/main/java/org/apache/aurora/scheduler/sla/SlaAlgorithm.java
index 0f67311..2d27ad9 100644
--- a/src/main/java/org/apache/aurora/scheduler/sla/SlaAlgorithm.java
+++ b/src/main/java/org/apache/aurora/scheduler/sla/SlaAlgorithm.java
@@ -365,7 +365,6 @@ interface SlaAlgorithm {
                   break;
 
                 case INIT:
-                case SANDBOX_DELETED:
                   // Ignore.
                   break;
 

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/main/java/org/apache/aurora/scheduler/state/TaskStateMachine.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/state/TaskStateMachine.java b/src/main/java/org/apache/aurora/scheduler/state/TaskStateMachine.java
index 86a8eb5..cb870f9 100644
--- a/src/main/java/org/apache/aurora/scheduler/state/TaskStateMachine.java
+++ b/src/main/java/org/apache/aurora/scheduler/state/TaskStateMachine.java
@@ -48,7 +48,6 @@ import static org.apache.aurora.scheduler.state.SideEffect.Action.INCREMENT_FAIL
 import static org.apache.aurora.scheduler.state.SideEffect.Action.KILL;
 import static org.apache.aurora.scheduler.state.SideEffect.Action.RESCHEDULE;
 import static org.apache.aurora.scheduler.state.SideEffect.Action.SAVE_STATE;
-import static org.apache.aurora.scheduler.state.SideEffect.Action.STATE_CHANGE;
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.ASSIGNED;
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.DELETED;
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.DRAINING;
@@ -62,7 +61,6 @@ import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.PENDI
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.PREEMPTING;
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.RESTARTING;
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.RUNNING;
-import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.SANDBOX_DELETED;
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.STARTING;
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.THROTTLED;
 
@@ -119,7 +117,6 @@ class TaskStateMachine {
     KILLED(Optional.of(ScheduleStatus.KILLED)),
     KILLING(Optional.of(ScheduleStatus.KILLING)),
     LOST(Optional.of(ScheduleStatus.LOST)),
-    SANDBOX_DELETED(Optional.of(ScheduleStatus.SANDBOX_DELETED)),
     /**
      * The task does not have an associated state as it has been deleted from the store.
      */
@@ -215,10 +212,6 @@ class TaskStateMachine {
                 addFollowup(RESCHEDULE);
                 break;
 
-              case SANDBOX_DELETED:
-                addFollowupTransition(LOST);
-                break;
-
               default:
                 // No-op.
             }
@@ -362,12 +355,6 @@ class TaskStateMachine {
                             addFollowup(RESCHEDULE);
                             break;
 
-                          case SANDBOX_DELETED:
-                            // The slave previously acknowledged that it had the task, and now
-                            // stopped reporting it.
-                            addFollowupTransition(LOST);
-                            break;
-
                           default:
                             // No-op.
                         }
@@ -414,10 +401,6 @@ class TaskStateMachine {
                             addFollowup(RESCHEDULE);
                             break;
 
-                          case SANDBOX_DELETED:
-                            addFollowupTransition(LOST);
-                            break;
-
                            default:
                              // No-op.
                         }
@@ -426,7 +409,7 @@ class TaskStateMachine {
                 ))
         .addState(
             Rule.from(FINISHED)
-                .to(SANDBOX_DELETED, DELETED)
+                .to(DELETED)
                 .withCallback(manageTerminatedTasks))
         .addState(
             Rule.from(PREEMPTING)
@@ -442,23 +425,19 @@ class TaskStateMachine {
                 .withCallback(manageRestartingTask))
         .addState(
             Rule.from(FAILED)
-                .to(SANDBOX_DELETED, DELETED)
+                .to(DELETED)
                 .withCallback(manageTerminatedTasks))
         .addState(
             Rule.from(KILLED)
-                .to(SANDBOX_DELETED, DELETED)
+                .to(DELETED)
                 .withCallback(manageTerminatedTasks))
         // TODO(maxim): Re-evaluate if *DELETED states are valid transitions here.
         .addState(
             Rule.from(KILLING)
-                .to(FINISHED, FAILED, KILLED, LOST, SANDBOX_DELETED, DELETED)
+                .to(FINISHED, FAILED, KILLED, LOST, DELETED)
                 .withCallback(manageTerminatedTasks))
         .addState(
             Rule.from(LOST)
-                .to(SANDBOX_DELETED, DELETED)
-                .withCallback(manageTerminatedTasks))
-        .addState(
-            Rule.from(SANDBOX_DELETED)
                 .to(DELETED)
                 .withCallback(manageTerminatedTasks))
         .addState(
@@ -506,10 +485,6 @@ class TaskStateMachine {
     addFollowup(new SideEffect(action, Optional.<ScheduleStatus>absent()));
   }
 
-  private void addFollowupTransition(TaskState state) {
-    addFollowup(new SideEffect(STATE_CHANGE, state.getStatus()));
-  }
-
   private void addFollowup(SideEffect sideEffect) {
     LOG.info("Adding work command " + sideEffect + " for " + this);
     sideEffects.add(sideEffect);

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/main/java/org/apache/aurora/scheduler/storage/StorageBackfill.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/storage/StorageBackfill.java b/src/main/java/org/apache/aurora/scheduler/storage/StorageBackfill.java
index 8c20ab6..3b3cef2 100644
--- a/src/main/java/org/apache/aurora/scheduler/storage/StorageBackfill.java
+++ b/src/main/java/org/apache/aurora/scheduler/storage/StorageBackfill.java
@@ -13,6 +13,7 @@
  */
 package org.apache.aurora.scheduler.storage;
 
+import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.logging.Logger;
@@ -36,7 +37,6 @@ import org.apache.aurora.scheduler.storage.Storage.MutableStoreProvider;
 import org.apache.aurora.scheduler.storage.TaskStore.Mutable.TaskMutation;
 import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
 import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
-
 /**
  * Utility class to contain and perform storage backfill operations.
  */
@@ -99,6 +99,19 @@ public final class StorageBackfill {
     }
   }
 
+  private static void rewriteSandboxDeletedState(ScheduledTask task) {
+    if (task.getStatus() == ScheduleStatus.SANDBOX_DELETED) {
+      List<TaskEvent> events = task.getTaskEvents();
+      ScheduleStatus previousStatus = events.get(events.size() - 2).getStatus();
+
+      // Set the status to the previous event and drop the last event.
+      task.setStatus(previousStatus);
+      events.remove(events.size() - 1);
+
+      LOG.info("Rewriting SANDBOX_DELETED status to " + previousStatus + " for " + Tasks.id(task));
+    }
+  }
+
   /**
    * Backfills the storage to make it match any assumptions that may have changed since
    * the structs were first written.
@@ -118,6 +131,7 @@ public final class StorageBackfill {
         // TODO(ksweeney): Guarantee tasks pass current validation code here and quarantine if they
         // don't.
         guaranteeShardUniqueness(builder, storeProvider.getUnsafeTaskStore(), clock);
+        rewriteSandboxDeletedState(builder);
         return IScheduledTask.build(builder);
       }
     });

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/main/python/apache/aurora/executor/gc_executor.py
----------------------------------------------------------------------
diff --git a/src/main/python/apache/aurora/executor/gc_executor.py b/src/main/python/apache/aurora/executor/gc_executor.py
index 9b40ada..9c24771 100644
--- a/src/main/python/apache/aurora/executor/gc_executor.py
+++ b/src/main/python/apache/aurora/executor/gc_executor.py
@@ -278,6 +278,9 @@ class ThermosGCExecutor(ExecutorBase, ExceptionalThread, Observable):
         states = self.get_states(task_id)
         if states:
           _, last_state = states[-1]
+          # TODO(maxim): The SANDBOX_DELETED below is used as a safety fallback in case an unknown
+          # status is encountered during reconciliation. Unless GC executor is removed first
+          # (AURORA-715), consider a different fallback when removing the state
           updates[task_id] = THERMOS_TO_TWITTER_STATES.get(
               last_state,
               ScheduleStatus.SANDBOX_DELETED)

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/main/resources/scheduler/assets/js/controllers.js
----------------------------------------------------------------------
diff --git a/src/main/resources/scheduler/assets/js/controllers.js b/src/main/resources/scheduler/assets/js/controllers.js
index 7e9037e..f8e2eb7 100644
--- a/src/main/resources/scheduler/assets/js/controllers.js
+++ b/src/main/resources/scheduler/assets/js/controllers.js
@@ -509,11 +509,7 @@
           return taskEvent.timestamp;
         });
 
-        // Since all task sandboxes are eventually garbage collected SANDBOX_DELETED doesn't
-        // indicate the state of the task, so use the previous task event to determine task status.
-        var latestTaskEvent = task.status === ScheduleStatus.SANDBOX_DELETED ?
-          _.chain(sortedTaskEvents).last(2).first().value() :
-          _.last(sortedTaskEvents);
+        var latestTaskEvent = _.last(sortedTaskEvents);
 
         return {
           instanceId: task.assignedTask.instanceId,
@@ -526,7 +522,8 @@
           taskId: task.assignedTask.taskId,
           taskEvents: summarizeTaskEvents(sortedTaskEvents),
           showDetails: false,
-          sandboxExists: task.status !== ScheduleStatus.SANDBOX_DELETED
+          // TODO(maxim): Revisit this approach when the UI fix in AURORA-715 is finalized.
+          sandboxExists: true
         };
       }
 

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/main/resources/scheduler/assets/js/filters.js
----------------------------------------------------------------------
diff --git a/src/main/resources/scheduler/assets/js/filters.js b/src/main/resources/scheduler/assets/js/filters.js
index 7e8ca84..bf6aef8 100644
--- a/src/main/resources/scheduler/assets/js/filters.js
+++ b/src/main/resources/scheduler/assets/js/filters.js
@@ -35,8 +35,7 @@
       KILLING: 'A user request or cron invocation has requested the task be killed.',
       LOST: 'The task cannot be accounted for, usually a result of slave process or machine ' +
         'failure.',
-      DRAINING: 'The task is being restarted since the host is undergoing scheduled maintenance.',
-      SANDBOX_DELETED: 'The task sandbox has been deleted by the executor.'
+      DRAINING: 'The task is being restarted since the host is undergoing scheduled maintenance.'
     };
 
     return function (value) {

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/main/thrift/org/apache/aurora/gen/api.thrift
----------------------------------------------------------------------
diff --git a/src/main/thrift/org/apache/aurora/gen/api.thrift b/src/main/thrift/org/apache/aurora/gen/api.thrift
index 77092bd..4010836 100644
--- a/src/main/thrift/org/apache/aurora/gen/api.thrift
+++ b/src/main/thrift/org/apache/aurora/gen/api.thrift
@@ -356,6 +356,7 @@ enum ScheduleStatus {
    * This can happen, for example, when a slave process disappears.
    */
   LOST             = 7,
+  // TODO(maxim): Remove SANDBOX_DELETED in 0.7.0. (AURORA-832)
   /** The task sandbox has been deleted by the executor. */
   SANDBOX_DELETED  = 10
 }

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java b/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java
index 606c443..c405d4c 100644
--- a/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java
+++ b/src/test/java/org/apache/aurora/scheduler/app/SchedulerIT.java
@@ -353,7 +353,6 @@ public class SchedulerIT extends BaseZooKeeperTest {
     assertEquals(0L, Stats.<Long>getVariable("task_store_PENDING").read().longValue());
     assertEquals(1L, Stats.<Long>getVariable("task_store_ASSIGNED").read().longValue());
     assertEquals(1L, Stats.<Long>getVariable("task_store_RUNNING").read().longValue());
-    assertEquals(0L, Stats.<Long>getVariable("task_store_SANDBOX_DELETED").read().longValue());
 
     // TODO(William Farner): Send a thrift RPC to the scheduler.
     // TODO(William Farner): Also send an admin thrift RPC to verify capability (e.g. ROOT) mapping.

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/test/java/org/apache/aurora/scheduler/async/GcExecutorLauncherTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/async/GcExecutorLauncherTest.java b/src/test/java/org/apache/aurora/scheduler/async/GcExecutorLauncherTest.java
index d77f521..059a276 100644
--- a/src/test/java/org/apache/aurora/scheduler/async/GcExecutorLauncherTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/async/GcExecutorLauncherTest.java
@@ -55,7 +55,6 @@ import org.junit.Before;
 import org.junit.Test;
 
 import static org.apache.aurora.gen.ScheduleStatus.FAILED;
-import static org.apache.aurora.gen.ScheduleStatus.SANDBOX_DELETED;
 import static org.apache.aurora.scheduler.async.GcExecutorLauncher.INSUFFICIENT_OFFERS_STAT_NAME;
 import static org.apache.aurora.scheduler.async.GcExecutorLauncher.LOST_TASKS_STAT_NAME;
 import static org.apache.aurora.scheduler.async.GcExecutorLauncher.SYSTEM_TASK_PREFIX;
@@ -216,24 +215,6 @@ public class GcExecutorLauncherTest extends EasyMockTest {
     assertEquals(0, insufficientOffers.get());
   }
 
-  @Test
-  public void testFiltersSandboxDeleted() {
-    IScheduledTask a = makeTask(JOB_A, FAILED);
-    IScheduledTask b = makeTask(JOB_A, SANDBOX_DELETED);
-
-    expectGetTasksByHost(HOST, a, b);
-    expectAdjustRetainedTasks(a);
-
-    replayAndConstruct();
-
-    // First call - no items in the cache, no tasks collected.
-    assertFalse(gcExecutorLauncher.willUse(OFFER));
-
-    // Second call - host item expires initial delay, one task collected.
-    clock.advance(Amount.of(1L, Time.HOURS));
-    assertTrue(gcExecutorLauncher.willUse(OFFER));
-  }
-
   private void expectAdjustRetainedTasks(IScheduledTask... tasks) {
     Map<String, ScheduleStatus> statuses =
         Maps.transformValues(Tasks.mapById(ImmutableSet.copyOf(tasks)), Tasks.GET_STATUS);

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/test/java/org/apache/aurora/scheduler/async/TaskHistoryPrunerTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/async/TaskHistoryPrunerTest.java b/src/test/java/org/apache/aurora/scheduler/async/TaskHistoryPrunerTest.java
index 53d2c6b..b3e4ae3 100644
--- a/src/test/java/org/apache/aurora/scheduler/async/TaskHistoryPrunerTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/async/TaskHistoryPrunerTest.java
@@ -56,7 +56,6 @@ import static org.apache.aurora.gen.ScheduleStatus.FINISHED;
 import static org.apache.aurora.gen.ScheduleStatus.KILLED;
 import static org.apache.aurora.gen.ScheduleStatus.LOST;
 import static org.apache.aurora.gen.ScheduleStatus.RUNNING;
-import static org.apache.aurora.gen.ScheduleStatus.SANDBOX_DELETED;
 import static org.apache.aurora.gen.ScheduleStatus.STARTING;
 import static org.easymock.EasyMock.eq;
 import static org.easymock.EasyMock.expectLastCall;
@@ -102,7 +101,7 @@ public class TaskHistoryPrunerTest extends EasyMockTest {
 
     clock.advance(ONE_MS);
     long taskBTimestamp = clock.nowMillis();
-    IScheduledTask b = makeTask("b", SANDBOX_DELETED);
+    IScheduledTask b = makeTask("b", LOST);
 
     expectNoImmediatePrune(ImmutableSet.of(a));
     expectOneDelayedPrune(taskATimestamp);
@@ -118,7 +117,7 @@ public class TaskHistoryPrunerTest extends EasyMockTest {
   @Test
   public void testStorageStartedWithPruning() {
     long taskATimestamp = clock.nowMillis();
-    IScheduledTask a = makeTask("a", SANDBOX_DELETED);
+    IScheduledTask a = makeTask("a", FINISHED);
 
     clock.advance(ONE_MINUTE);
     long taskBTimestamp = clock.nowMillis();

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/test/java/org/apache/aurora/scheduler/base/JobsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/base/JobsTest.java b/src/test/java/org/apache/aurora/scheduler/base/JobsTest.java
index f3b6ff0..56d49ea 100644
--- a/src/test/java/org/apache/aurora/scheduler/base/JobsTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/base/JobsTest.java
@@ -14,10 +14,12 @@
 package org.apache.aurora.scheduler.base;
 
 import java.util.Arrays;
+import java.util.Set;
 
 import com.google.common.base.Function;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 
 import org.apache.aurora.gen.JobStats;
@@ -34,28 +36,24 @@ public class JobsTest {
 
   @Test
   public void testGetJobStats() {
+    // TODO(maxim): Drop when AURORA-832 is fixed.
+    Set<ScheduleStatus> statusValues = Sets.difference(
+        Sets.immutableEnumSet(Arrays.asList(ScheduleStatus.values())),
+        ImmutableSet.of(ScheduleStatus.SANDBOX_DELETED));
+
     ImmutableList<IScheduledTask> tasks =
         FluentIterable
-            .from(Sets.immutableEnumSet(Arrays.asList(ScheduleStatus.values())))
+            .from(statusValues)
             .transform(new Function<ScheduleStatus, IScheduledTask>() {
               @Override
               public IScheduledTask apply(ScheduleStatus status) {
-                int startTime = 100;
-                if (status == ScheduleStatus.SANDBOX_DELETED) {
-                  return makeTask(
-                      status,
-                      makeTaskEvents(
-                          startTime,
-                          ScheduleStatus.FAILED,
-                          ScheduleStatus.SANDBOX_DELETED));
-                }
-                return makeTask(status, makeTaskEvents(startTime, status));
+                return makeTask(status, makeTaskEvents(100, status));
               }
             }).toList();
 
     IJobStats expectedStats = IJobStats.build(new JobStats()
         .setActiveTaskCount(7)
-        .setFailedTaskCount(3)
+        .setFailedTaskCount(2)
         .setFinishedTaskCount(2)
         .setPendingTaskCount(3));
 

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/test/java/org/apache/aurora/scheduler/sla/SlaAlgorithmTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/sla/SlaAlgorithmTest.java b/src/test/java/org/apache/aurora/scheduler/sla/SlaAlgorithmTest.java
index eccf0c7..d36f565 100644
--- a/src/test/java/org/apache/aurora/scheduler/sla/SlaAlgorithmTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/sla/SlaAlgorithmTest.java
@@ -34,7 +34,6 @@ import static org.apache.aurora.gen.ScheduleStatus.LOST;
 import static org.apache.aurora.gen.ScheduleStatus.PENDING;
 import static org.apache.aurora.gen.ScheduleStatus.RESTARTING;
 import static org.apache.aurora.gen.ScheduleStatus.RUNNING;
-import static org.apache.aurora.gen.ScheduleStatus.SANDBOX_DELETED;
 import static org.apache.aurora.gen.ScheduleStatus.STARTING;
 import static org.apache.aurora.scheduler.sla.SlaAlgorithm.AlgorithmType.AGGREGATE_PLATFORM_UPTIME;
 import static org.apache.aurora.scheduler.sla.SlaAlgorithm.AlgorithmType.JOB_UPTIME_50;
@@ -268,15 +267,6 @@ public class SlaAlgorithmTest {
   }
 
   @Test
-  public void AggregatePlatformUptimeSandboxDeletedIgnoredTest() {
-    Number actual = AGGREGATE_PLATFORM_UPTIME.getAlgorithm().calculate(
-        ImmutableSet.of(
-            makeTask(ImmutableMap.of(50L, RUNNING, 300L, LOST, 400L, SANDBOX_DELETED), 0)),
-        Range.closedOpen(100L, 500L));
-    assertEquals(50.0, actual);
-  }
-
-  @Test
   public void AggregatePlatformUptimeEmptyTest() {
     Number actual = AGGREGATE_PLATFORM_UPTIME.getAlgorithm().calculate(
         ImmutableSet.of(makeTask(ImmutableMap.of(50L, PENDING), 0)),

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/test/java/org/apache/aurora/scheduler/state/StateManagerImplTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/state/StateManagerImplTest.java b/src/test/java/org/apache/aurora/scheduler/state/StateManagerImplTest.java
index 7b67c24..cf4a015 100644
--- a/src/test/java/org/apache/aurora/scheduler/state/StateManagerImplTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/state/StateManagerImplTest.java
@@ -64,7 +64,6 @@ import static org.apache.aurora.gen.ScheduleStatus.KILLING;
 import static org.apache.aurora.gen.ScheduleStatus.LOST;
 import static org.apache.aurora.gen.ScheduleStatus.PENDING;
 import static org.apache.aurora.gen.ScheduleStatus.RUNNING;
-import static org.apache.aurora.gen.ScheduleStatus.SANDBOX_DELETED;
 import static org.apache.aurora.gen.ScheduleStatus.THROTTLED;
 import static org.easymock.EasyMock.expect;
 import static org.easymock.EasyMock.expectLastCall;
@@ -228,7 +227,7 @@ public class StateManagerImplTest extends EasyMockTest {
     ITaskConfig task = makeTask(JIM, MY_JOB);
     String taskId = "a";
     expect(taskIdGenerator.generate(task, 0)).andReturn(taskId);
-    expectStateTransitions(taskId, INIT, PENDING, ASSIGNED, RUNNING, KILLING, SANDBOX_DELETED);
+    expectStateTransitions(taskId, INIT, PENDING, ASSIGNED, RUNNING, KILLING, LOST);
 
     driver.killTask(EasyMock.<String>anyObject());
 
@@ -239,7 +238,7 @@ public class StateManagerImplTest extends EasyMockTest {
     assignTask(taskId, HOST_A);
     changeState(taskId, RUNNING);
     changeState(taskId, KILLING);
-    changeState(taskId, SANDBOX_DELETED);
+    changeState(taskId, LOST);
   }
 
   @Test
@@ -342,29 +341,6 @@ public class StateManagerImplTest extends EasyMockTest {
   }
 
   @Test
-  public void testDoubleTransition() {
-    // Tests that a transition inducing another transition (STATE_CHANGE action) is performed.
-
-    ITaskConfig task = makeTask(JIM, MY_JOB);
-    String taskId = "a";
-    expect(taskIdGenerator.generate(task, 0)).andReturn(taskId);
-    expectStateTransitions(taskId, INIT, PENDING, ASSIGNED, RUNNING, LOST);
-
-    String taskId2 = "a2";
-    expect(taskIdGenerator.generate(task, 0)).andReturn(taskId2);
-    noFlappingPenalty();
-    expectStateTransitions(taskId2, INIT, PENDING);
-
-    control.replay();
-
-    insertTask(task, 0);
-
-    assignTask(taskId, HOST_A);
-    changeState(taskId, RUNNING);
-    changeState(taskId, SANDBOX_DELETED);
-  }
-
-  @Test
   public void testCasTaskPresent() {
     ITaskConfig task = makeTask(JIM, MY_JOB);
     String taskId = "a";

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/test/java/org/apache/aurora/scheduler/state/TaskStateMachineTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/state/TaskStateMachineTest.java b/src/test/java/org/apache/aurora/scheduler/state/TaskStateMachineTest.java
index cb32547..50d387d 100644
--- a/src/test/java/org/apache/aurora/scheduler/state/TaskStateMachineTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/state/TaskStateMachineTest.java
@@ -50,7 +50,6 @@ import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.PENDI
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.PREEMPTING;
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.RESTARTING;
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.RUNNING;
-import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.SANDBOX_DELETED;
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.STARTING;
 import static org.apache.aurora.scheduler.state.TaskStateMachine.TaskState.THROTTLED;
 import static org.junit.Assert.assertEquals;
@@ -77,7 +76,7 @@ public class TaskStateMachineTest {
   @Test
   public void testSimpleTransition() {
     expectUpdateStateOnTransitionTo(PENDING, ASSIGNED, STARTING, RUNNING, FINISHED);
-    legalTransition(SANDBOX_DELETED, Action.SAVE_STATE);
+    legalTransition(DELETED, Action.DELETE);
   }
 
   @Test
@@ -127,50 +126,10 @@ public class TaskStateMachineTest {
   }
 
   @Test
-  public void testTerminalToSandboxDeleted() {
-    Set<ScheduleStatus> terminalStates =
-        Sets.difference(Tasks.TERMINAL_STATES, ImmutableSet.of(ScheduleStatus.SANDBOX_DELETED));
-    System.out.print(terminalStates);
-    for (ScheduleStatus endState : terminalStates) {
-      stateMachine = makeStateMachine(makeTask(false));
-      Set<SideEffect.Action> finalActions = Sets.newHashSet(Action.SAVE_STATE);
-
-      switch (endState) {
-        case FAILED:
-          finalActions.add(Action.INCREMENT_FAILURES);
-          break;
-
-        case FINISHED:
-          break;
-
-        case KILLED:
-        case LOST:
-          finalActions.add(Action.RESCHEDULE);
-          break;
-
-        case KILLING:
-          finalActions.add(Action.KILL);
-          break;
-
-        default:
-          fail("Unknown state " + endState);
-      }
-
-      expectUpdateStateOnTransitionTo(
-          PENDING,
-          ASSIGNED,
-          STARTING,
-          RUNNING);
-      legalTransition(TaskState.valueOf(endState.name()), finalActions);
-      legalTransition(SANDBOX_DELETED, Action.SAVE_STATE);
-    }
-  }
-
-  @Test
   public void testTerminalToDeleted() {
     Set<ScheduleStatus> terminalStates =
         Sets.difference(Tasks.TERMINAL_STATES, ImmutableSet.of(ScheduleStatus.SANDBOX_DELETED));
-    System.out.print(terminalStates);
+
     for (ScheduleStatus endState : terminalStates) {
       stateMachine = makeStateMachine(makeTask(false));
       Set<SideEffect.Action> finalActions = Sets.newHashSet(Action.SAVE_STATE);
@@ -207,19 +166,6 @@ public class TaskStateMachineTest {
   }
 
   @Test
-  public void testSandboxDeletedToDeleted() {
-    stateMachine = makeStateMachine(makeTask(false));
-    expectUpdateStateOnTransitionTo(
-        PENDING,
-        ASSIGNED,
-        STARTING,
-        RUNNING,
-        FINISHED,
-        SANDBOX_DELETED);
-    legalTransition(DELETED, Action.DELETE);
-  }
-
-  @Test
   public void testUnknownTask() {
     stateMachine = new TaskStateMachine("id");
 
@@ -239,20 +185,6 @@ public class TaskStateMachineTest {
   }
 
   @Test
-  public void testMissingStartingRescheduledImmediately() {
-    expectUpdateStateOnTransitionTo(PENDING, ASSIGNED, STARTING);
-    illegalTransition(SANDBOX_DELETED,
-        ImmutableSet.of(new SideEffect(Action.STATE_CHANGE, Optional.of(LOST.getStatus().get()))));
-  }
-
-  @Test
-  public void testMissingRunningRescheduledImmediately() {
-    expectUpdateStateOnTransitionTo(PENDING, ASSIGNED, STARTING, RUNNING);
-    illegalTransition(SANDBOX_DELETED,
-        ImmutableSet.of(new SideEffect(Action.STATE_CHANGE, Optional.of(LOST.getStatus().get()))));
-  }
-
-  @Test
   public void testRestartedTask() {
     expectUpdateStateOnTransitionTo(PENDING, ASSIGNED, STARTING, RUNNING);
     legalTransition(RESTARTING, Action.SAVE_STATE, Action.KILL);
@@ -511,7 +443,6 @@ public class TaskStateMachineTest {
           .put(new TestCase(true, STARTING, KILLED), SAVE_AND_RESCHEDULE)
           .put(new TestCase(true, STARTING, KILLING), SAVE_AND_KILL)
           .put(new TestCase(true, STARTING, LOST), SAVE_AND_RESCHEDULE)
-          .put(new TestCase(true, STARTING, SANDBOX_DELETED), MARK_LOST)
           .put(new TestCase(false, RUNNING, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(false, RUNNING, STARTING), ILLEGAL_KILL)
           .put(new TestCase(false, RUNNING, RUNNING), ILLEGAL_KILL)
@@ -523,14 +454,12 @@ public class TaskStateMachineTest {
           .put(new TestCase(true, RUNNING, KILLED), SAVE_AND_RESCHEDULE)
           .put(new TestCase(true, RUNNING, KILLING), SAVE_AND_KILL)
           .put(new TestCase(true, RUNNING, LOST), SAVE_AND_RESCHEDULE)
-          .put(new TestCase(true, RUNNING, SANDBOX_DELETED), MARK_LOST)
           .put(new TestCase(true, FINISHED, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(false, FINISHED, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(true, FINISHED, STARTING), ILLEGAL_KILL)
           .put(new TestCase(false, FINISHED, STARTING), ILLEGAL_KILL)
           .put(new TestCase(true, FINISHED, RUNNING), ILLEGAL_KILL)
           .put(new TestCase(false, FINISHED, RUNNING), ILLEGAL_KILL)
-          .put(new TestCase(true, FINISHED, SANDBOX_DELETED), SAVE)
           .put(new TestCase(true, FINISHED, DELETED), DELETE_TASK)
           .put(new TestCase(true, PREEMPTING, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(false, PREEMPTING, ASSIGNED), ILLEGAL_KILL)
@@ -543,7 +472,6 @@ public class TaskStateMachineTest {
           .put(new TestCase(true, PREEMPTING, KILLED), SAVE_AND_RESCHEDULE)
           .put(new TestCase(true, PREEMPTING, KILLING), SAVE)
           .put(new TestCase(true, PREEMPTING, LOST), SAVE_KILL_AND_RESCHEDULE)
-          .put(new TestCase(true, PREEMPTING, SANDBOX_DELETED), MARK_LOST)
           .put(new TestCase(true, RESTARTING, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(false, RESTARTING, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(true, RESTARTING, STARTING), ILLEGAL_KILL)
@@ -555,7 +483,6 @@ public class TaskStateMachineTest {
           .put(new TestCase(true, RESTARTING, KILLED), SAVE_AND_RESCHEDULE)
           .put(new TestCase(true, RESTARTING, KILLING), SAVE)
           .put(new TestCase(true, RESTARTING, LOST), SAVE_KILL_AND_RESCHEDULE)
-          .put(new TestCase(true, RESTARTING, SANDBOX_DELETED), MARK_LOST)
           .put(new TestCase(true, DRAINING, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(false, DRAINING, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(true, DRAINING, STARTING), ILLEGAL_KILL)
@@ -567,14 +494,12 @@ public class TaskStateMachineTest {
           .put(new TestCase(true, DRAINING, KILLED), SAVE_AND_RESCHEDULE)
           .put(new TestCase(true, DRAINING, KILLING), SAVE)
           .put(new TestCase(true, DRAINING, LOST), SAVE_KILL_AND_RESCHEDULE)
-          .put(new TestCase(true, DRAINING, SANDBOX_DELETED), MARK_LOST)
           .put(new TestCase(true, FAILED, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(false, FAILED, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(true, FAILED, STARTING), ILLEGAL_KILL)
           .put(new TestCase(false, FAILED, STARTING), ILLEGAL_KILL)
           .put(new TestCase(true, FAILED, RUNNING), ILLEGAL_KILL)
           .put(new TestCase(false, FAILED, RUNNING), ILLEGAL_KILL)
-          .put(new TestCase(true, FAILED, SANDBOX_DELETED), SAVE)
           .put(new TestCase(true, FAILED, DELETED), DELETE_TASK)
           .put(new TestCase(true, KILLED, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(false, KILLED, ASSIGNED), ILLEGAL_KILL)
@@ -582,7 +507,6 @@ public class TaskStateMachineTest {
           .put(new TestCase(false, KILLED, STARTING), ILLEGAL_KILL)
           .put(new TestCase(true, KILLED, RUNNING), ILLEGAL_KILL)
           .put(new TestCase(false, KILLED, RUNNING), ILLEGAL_KILL)
-          .put(new TestCase(true, KILLED, SANDBOX_DELETED), SAVE)
           .put(new TestCase(true, KILLED, DELETED), DELETE_TASK)
           .put(new TestCase(true, KILLING, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(false, KILLING, ASSIGNED), ILLEGAL_KILL)
@@ -594,7 +518,6 @@ public class TaskStateMachineTest {
           .put(new TestCase(true, KILLING, FAILED), SAVE)
           .put(new TestCase(true, KILLING, KILLED), SAVE)
           .put(new TestCase(true, KILLING, LOST), SAVE)
-          .put(new TestCase(true, KILLING, SANDBOX_DELETED), SAVE)
           .put(new TestCase(true, KILLING, DELETED), DELETE_TASK)
           .put(new TestCase(true, LOST, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(false, LOST, ASSIGNED), ILLEGAL_KILL)
@@ -602,15 +525,7 @@ public class TaskStateMachineTest {
           .put(new TestCase(false, LOST, STARTING), ILLEGAL_KILL)
           .put(new TestCase(true, LOST, RUNNING), ILLEGAL_KILL)
           .put(new TestCase(false, LOST, RUNNING), ILLEGAL_KILL)
-          .put(new TestCase(true, LOST, SANDBOX_DELETED), SAVE)
           .put(new TestCase(true, LOST, DELETED), DELETE_TASK)
-          .put(new TestCase(true, SANDBOX_DELETED, ASSIGNED), ILLEGAL_KILL)
-          .put(new TestCase(false, SANDBOX_DELETED, ASSIGNED), ILLEGAL_KILL)
-          .put(new TestCase(true, SANDBOX_DELETED, STARTING), ILLEGAL_KILL)
-          .put(new TestCase(false, SANDBOX_DELETED, STARTING), ILLEGAL_KILL)
-          .put(new TestCase(true, SANDBOX_DELETED, RUNNING), ILLEGAL_KILL)
-          .put(new TestCase(false, SANDBOX_DELETED, RUNNING), ILLEGAL_KILL)
-          .put(new TestCase(true, SANDBOX_DELETED, DELETED), DELETE_TASK)
           .put(new TestCase(false, DELETED, ASSIGNED), ILLEGAL_KILL)
           .put(new TestCase(false, DELETED, STARTING), ILLEGAL_KILL)
           .put(new TestCase(false, DELETED, RUNNING), ILLEGAL_KILL)

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/ffa126d6/src/test/java/org/apache/aurora/scheduler/storage/StorageBackfillTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/storage/StorageBackfillTest.java b/src/test/java/org/apache/aurora/scheduler/storage/StorageBackfillTest.java
index 80646a6..0c1a271 100644
--- a/src/test/java/org/apache/aurora/scheduler/storage/StorageBackfillTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/storage/StorageBackfillTest.java
@@ -41,13 +41,16 @@ import org.apache.aurora.scheduler.storage.entities.IJobConfiguration;
 import org.apache.aurora.scheduler.storage.entities.IJobKey;
 import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
 import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
+import org.apache.aurora.scheduler.storage.entities.ITaskEvent;
 import org.apache.aurora.scheduler.storage.mem.MemStorage;
 import org.junit.Before;
 import org.junit.Test;
 
+import static org.apache.aurora.gen.ScheduleStatus.FINISHED;
 import static org.apache.aurora.gen.ScheduleStatus.KILLED;
 import static org.apache.aurora.gen.ScheduleStatus.PENDING;
 import static org.apache.aurora.gen.ScheduleStatus.RUNNING;
+import static org.apache.aurora.gen.ScheduleStatus.SANDBOX_DELETED;
 import static org.junit.Assert.assertEquals;
 
 public class StorageBackfillTest {
@@ -72,6 +75,33 @@ public class StorageBackfillTest {
   }
 
   @Test
+  public void testRewriteSandboxDeleted() throws Exception {
+    final TaskConfig storedTask = defaultTask();
+    final TaskEvent expectedEvent = new TaskEvent(100, FINISHED);
+
+    storage.write(new Storage.MutateWork.NoResult.Quiet() {
+      @Override
+      protected void execute(Storage.MutableStoreProvider storeProvider) {
+        storeProvider.getUnsafeTaskStore().saveTasks(ImmutableSet.of(
+            IScheduledTask.build(new ScheduledTask()
+                .setStatus(SANDBOX_DELETED)
+                .setTaskEvents(ImmutableList.of(expectedEvent, new TaskEvent(200, SANDBOX_DELETED)))
+                .setAssignedTask(new AssignedTask()
+                    .setTaskId(TASK_ID)
+                    .setInstanceId(0)
+                    .setTask(storedTask)))));
+      }
+    });
+
+    backfill();
+
+    assertEquals(FINISHED, getTask(TASK_ID).getStatus());
+    assertEquals(
+        ImmutableList.of(ITaskEvent.build(expectedEvent)),
+        getTask(TASK_ID).getTaskEvents());
+  }
+
+  @Test
   public void testLoadTasksFromStorage() throws Exception {
     final TaskConfig storedTask = defaultTask();