Implement Detached Actor (#6036)

* Arg propagation works

* Implement persistent actor

* Add doc

* Initialize is_persistent_

* Rename persistent->detached

* Address comment

* Make test passes

* Address comment

* Python2 compatiblity

* Fix naming, py2

* Lint
This commit is contained in:
Simon Mo
2019-11-01 10:28:23 -07:00
committed by GitHub
parent f7455839bf
commit 7f5b3502da
16 changed files with 164 additions and 27 deletions
+4 -2
View File
@@ -948,7 +948,8 @@ cdef class CoreWorker:
uint64_t max_reconstructions,
resources,
placement_resources,
c_bool is_direct_call):
c_bool is_direct_call,
c_bool is_detached):
cdef:
CRayFunction ray_function
c_vector[CTaskArg] args_vector
@@ -969,7 +970,8 @@ cdef class CoreWorker:
ray_function, args_vector,
CActorCreationOptions(
max_reconstructions, is_direct_call, c_resources,
c_placement_resources, dynamic_worker_options),
c_placement_resources, dynamic_worker_options,
is_detached),
&c_actor_id))
return ActorID(c_actor_id.Binary())
+27 -2
View File
@@ -307,7 +307,9 @@ class ActorClass(object):
memory=None,
object_store_memory=None,
resources=None,
is_direct_call=None):
is_direct_call=None,
name=None,
detached=False):
"""Create an actor.
This method allows more flexibility than the remote method because
@@ -325,6 +327,9 @@ class ActorClass(object):
resources: The custom resources required by the actor creation
task.
is_direct_call: Use direct actor calls.
name: The globally unique name for the actor.
detached: Whether the actor should be kept alive after driver
exits.
Returns:
A handle to the newly created actor.
@@ -341,6 +346,23 @@ class ActorClass(object):
meta = self.__ray_metadata__
if detached and name is None:
raise Exception("Detached actors must be named. "
"Please use Actor._remote(name='some_name') "
"to associate the name.")
# Check whether the name is already taken.
if name is not None:
try:
ray.experimental.get_actor(name)
except ValueError: # name is not taken, expected.
pass
else:
raise ValueError(
"The name {name} is already taken. Please use "
"a different name or get existing actor using "
"ray.experimental.get_actor('{name}')".format(name=name))
# Set the actor's default resources if not already set. First three
# conditions are to check that no resources were specified in the
# decorator. Last three conditions are to check that no resources were
@@ -403,7 +425,7 @@ class ActorClass(object):
actor_id = worker.core_worker.create_actor(
function_descriptor.get_function_descriptor_list(),
creation_args, meta.max_reconstructions, resources,
actor_placement_resources, is_direct_call)
actor_placement_resources, is_direct_call, detached)
actor_handle = ActorHandle(
actor_id,
@@ -417,6 +439,9 @@ class ActorClass(object):
worker.current_session_and_job,
original_handle=True)
if name is not None:
ray.experimental.register_actor(name, actor_handle)
return actor_handle
+2 -1
View File
@@ -207,7 +207,8 @@ cdef extern from "ray/core_worker/common.h" nogil:
uint64_t max_reconstructions, c_bool is_direct_call,
const unordered_map[c_string, double] &resources,
const unordered_map[c_string, double] &placement_resources,
const c_vector[c_string] &dynamic_worker_options)
const c_vector[c_string] &dynamic_worker_options,
c_bool is_detached)
cdef extern from "ray/gcs/gcs_client_interface.h" nogil:
cdef cppclass CGcsClientOptions "ray::gcs::GcsClientOptions":
+37 -6
View File
@@ -21,12 +21,9 @@ import ray.ray_constants as ray_constants
import ray.tests.utils
import ray.tests.cluster_utils
from ray.tests.conftest import generate_internal_config_map
from ray.tests.utils import (
relevant_errors,
wait_for_condition,
wait_for_errors,
wait_for_pid_to_exit,
)
from ray.tests.utils import (relevant_errors, wait_for_condition,
wait_for_errors, wait_for_pid_to_exit,
run_string_as_driver)
@pytest.fixture
@@ -2816,3 +2813,37 @@ def test_ray_wait_dead_actor(ray_start_cluster):
failure_detected = False
while not failure_detected:
failure_detected = ray.get(parent_actor.wait.remote())
def test_detached_actor(ray_start_regular):
@ray.remote
class DetachedActor(object):
def ping(self):
return "pong"
with pytest.raises(Exception, match="Detached actors must be named"):
DetachedActor._remote(detached=True)
with pytest.raises(ValueError, match="Please use a different name"):
_ = DetachedActor._remote(name="d_actor")
DetachedActor._remote(name="d_actor")
redis_address = ray_start_regular["redis_address"]
actor_name = "DetachedActor"
driver_script = """
import ray
ray.init(address="{}")
@ray.remote
class DetachedActor(object):
def ping(self):
return "pong"
actor = DetachedActor._remote(name="{}", detached=True)
ray.get(actor.ping.remote())
""".format(redis_address, actor_name)
run_string_as_driver(driver_script)
detached_actor = ray.experimental.get_actor(actor_name)
assert ray.get(detached_actor.ping.remote()) == "pong"