Nondeterministic reconstruction for actors (#1344)

* Add failing unit test for nondeterministic reconstruction

* Retry scheduling actor tasks if reassigned to local scheduler

* Update execution edges asynchronously upon dispatch for nondeterministic reconstruction

* Fix bug for updating checkpoint task execution dependencies

* Update comments for deterministic reconstruction

* cleanup

* Add (and skip) failing test case for nondeterministic reconstruction

* Suppress test output
This commit is contained in:
Stephanie Wang
2018-01-21 13:44:13 -08:00
committed by GitHub
parent 83949a533b
commit 74718efa73
4 changed files with 144 additions and 19 deletions
+80
View File
@@ -1625,6 +1625,86 @@ class DistributedActorHandles(unittest.TestCase):
# self.assertRaises(Exception):
# ray.get(g.remote())
def _testNondeterministicReconstruction(self, num_forks,
num_items_per_fork,
num_forks_to_wait):
ray.worker._init(start_ray_local=True, num_local_schedulers=2,
num_workers=0, redirect_output=True)
# Make a shared queue.
@ray.remote
class Queue(object):
def __init__(self):
self.queue = []
def local_plasma(self):
return ray.worker.global_worker.plasma_client.store_socket_name
def push(self, item):
self.queue.append(item)
def read(self):
return self.queue
# Schedule the shared queue onto the remote local scheduler.
local_plasma = ray.worker.global_worker.plasma_client.store_socket_name
actor = Queue.remote()
while ray.get(actor.local_plasma.remote()) == local_plasma:
actor = Queue.remote()
# A task that takes in the shared queue and a list of items to enqueue,
# one by one.
@ray.remote
def enqueue(queue, items):
done = None
for item in items:
done = queue.push.remote(item)
# TODO(swang): Return the object ID returned by the last method
# called on the shared queue, so that the caller of enqueue can
# wait for all of the queue methods to complete. This can be
# removed once join consistency is implemented.
return [done]
# Call the enqueue task num_forks times, each with num_items_per_fork
# unique objects to push onto the shared queue.
enqueue_tasks = []
for fork in range(num_forks):
enqueue_tasks.append(enqueue.remote(
actor, [(fork, i) for i in range(num_items_per_fork)]))
# Wait for the forks to complete their tasks.
enqueue_tasks = ray.get(enqueue_tasks)
enqueue_tasks = [fork_ids[0] for fork_ids in enqueue_tasks]
ray.wait(enqueue_tasks, num_returns=num_forks_to_wait)
# Read the queue to get the initial order of execution.
queue = ray.get(actor.read.remote())
# Kill the second plasma store to get rid of the cached objects and
# trigger the corresponding local scheduler to exit.
process = ray.services.all_processes[
ray.services.PROCESS_TYPE_PLASMA_STORE][1]
process.kill()
process.wait()
# Read the queue again and check for deterministic reconstruction.
ray.get(enqueue_tasks)
reconstructed_queue = ray.get(actor.read.remote())
# Make sure the final queue has all items from all forks.
self.assertEqual(len(reconstructed_queue), num_forks *
num_items_per_fork)
# Make sure that the prefix of the final queue matches the queue from
# the initial execution.
self.assertEqual(queue, reconstructed_queue[:len(queue)])
def testNondeterministicReconstruction(self):
self._testNondeterministicReconstruction(10, 100, 10)
@unittest.skip("Nondeterministic reconstruction currently not supported "
"when there are concurrent forks that didn't finish "
"initial execution.")
def testNondeterministicReconstructionConcurrentForks(self):
self._testNondeterministicReconstruction(10, 100, 1)
@unittest.skip("Actor placement currently does not use custom resources.")
class ActorPlacement(unittest.TestCase):