mirror of
https://github.com/wassname/ray.git
synced 2026-06-27 21:38:18 +08:00
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:
@@ -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
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user