From 65a32e5556cbf5d7cf8892f1c7e737d7f4576056 Mon Sep 17 00:00:00 2001 From: Cindy Zhang Date: Tue, 16 May 2023 09:51:25 -0700 Subject: [PATCH 1/3] http proxy state shutdown Signed-off-by: Cindy Zhang --- python/ray/serve/_private/http_state.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/python/ray/serve/_private/http_state.py b/python/ray/serve/_private/http_state.py index e3c5e64c83b6..93e4487ef2d8 100644 --- a/python/ray/serve/_private/http_state.py +++ b/python/ray/serve/_private/http_state.py @@ -39,6 +39,7 @@ def __init__( self._status = HTTPProxyStatus.STARTING self._health_check_obj_ref = None self._last_health_check_time: float = 0 + self._deleting = False self._actor_details = HTTPProxyDetails( node_id=node_id, @@ -76,6 +77,9 @@ def update_actor_details(self, **kwargs) -> None: self._actor_details = HTTPProxyDetails(**details_kwargs) def update(self): + if self._deleting: + return + if self._status == HTTPProxyStatus.STARTING: try: finished, _ = ray.wait([self._ready_obj_ref], timeout=0) @@ -121,6 +125,10 @@ def update(self): self._health_check_obj_ref = self._actor_handle.check_health.remote() self._last_health_check_time = time.time() + def shutdown(self): + self._deleting = True + ray.kill(self.actor_handle, no_restart=True) + class HTTPState: """Manages all state for HTTP proxies in the system. @@ -157,8 +165,8 @@ def __init__( self._start_proxies_if_needed() def shutdown(self) -> None: - for proxy in self.get_http_proxy_handles().values(): - ray.kill(proxy, no_restart=True) + for proxy_state in self._proxy_states.values(): + proxy_state.shutdown() def get_config(self): return self._config From d3dd09541debb6a0e7fac5b980dbc30647aa7a87 Mon Sep 17 00:00:00 2001 From: Cindy Zhang Date: Tue, 16 May 2023 12:26:31 -0700 Subject: [PATCH 2/3] add unit test Signed-off-by: Cindy Zhang --- python/ray/serve/_private/http_state.py | 1 + python/ray/serve/tests/test_http_state.py | 39 +++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/python/ray/serve/_private/http_state.py b/python/ray/serve/_private/http_state.py index 93e4487ef2d8..d558bed51d77 100644 --- a/python/ray/serve/_private/http_state.py +++ b/python/ray/serve/_private/http_state.py @@ -101,6 +101,7 @@ def update(self): if finished: try: ray.get(finished[0]) + print("got object ref!") self.set_status(HTTPProxyStatus.HEALTHY) except Exception as e: logger.warning( diff --git a/python/ray/serve/tests/test_http_state.py b/python/ray/serve/tests/test_http_state.py index ae3870d292d5..19ce539c48ca 100644 --- a/python/ray/serve/tests/test_http_state.py +++ b/python/ray/serve/tests/test_http_state.py @@ -1,5 +1,6 @@ import json from unittest.mock import patch +import asyncio import pytest @@ -132,6 +133,44 @@ def check_proxy(status): ray.shutdown() +def test_http_proxy_shutdown(): + from ray.experimental.state.api import list_actors + ray.init() + + @ray.remote(num_cpus=0) + class MockHTTPProxyActor: + async def ready(self): + return json.dumps(["mock_worker_id", "mock_log_file_path"]) + + async def check_health(self): + await asyncio.sleep(100) + + proxy = MockHTTPProxyActor.options(lifetime="detached").remote() + state = HTTPProxyState(proxy, "alice", "mock_node_id", "mock_node_ip") + assert state.status == HTTPProxyStatus.STARTING + + def check_proxy(status): + state.update() + return state.status == status + + # Proxy actor is ready, so status should transition STARTING -> HEALTHY + wait_for_condition(check_proxy, status=HTTPProxyStatus.HEALTHY, timeout=2) + + # Confirm that a new health check has been started + state.update() + assert state._health_check_obj_ref + + # Shutdown the http proxy state. Wait for the http proxy actor to be killed + state.shutdown() + wait_for_condition(lambda: len(list_actors(filters=[("state", "=", "ALIVE")])) == 0) + + # Make sure that the state doesn't try to check on the status of the dead actor + state.update() + assert state.status == HTTPProxyStatus.HEALTHY + + ray.shutdown() + + if __name__ == "__main__": import sys From 53d6a0f684d4791343826fe21344c4612f15c06f Mon Sep 17 00:00:00 2001 From: Cindy Zhang Date: Tue, 16 May 2023 13:16:40 -0700 Subject: [PATCH 3/3] rename to shutting down Signed-off-by: Cindy Zhang --- python/ray/serve/_private/http_state.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ray/serve/_private/http_state.py b/python/ray/serve/_private/http_state.py index d558bed51d77..b9dde56abd5c 100644 --- a/python/ray/serve/_private/http_state.py +++ b/python/ray/serve/_private/http_state.py @@ -39,7 +39,7 @@ def __init__( self._status = HTTPProxyStatus.STARTING self._health_check_obj_ref = None self._last_health_check_time: float = 0 - self._deleting = False + self._shutting_down = False self._actor_details = HTTPProxyDetails( node_id=node_id, @@ -77,7 +77,7 @@ def update_actor_details(self, **kwargs) -> None: self._actor_details = HTTPProxyDetails(**details_kwargs) def update(self): - if self._deleting: + if self._shutting_down: return if self._status == HTTPProxyStatus.STARTING: @@ -127,7 +127,7 @@ def update(self): self._last_health_check_time = time.time() def shutdown(self): - self._deleting = True + self._shutting_down = True ray.kill(self.actor_handle, no_restart=True)