Skip to content

Commit 9c3b266

Browse files
committed
squash: SERVE-1216-abrar-auto vs origin/main @ e7a678e
Signed-off-by: abrar <abrar@anyscale.com>
1 parent e7a678e commit 9c3b266

File tree

10 files changed

+1550
-127
lines changed

10 files changed

+1550
-127
lines changed

ci/lint/pydoclint-baseline.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,10 +1528,6 @@ python/ray/serve/_private/api.py
15281528
DOC201: Function `serve_start` does not have a return section in docstring
15291529
--------------------
15301530
python/ray/serve/_private/application_state.py
1531-
DOC001: Method `__init__` Potential formatting errors in docstring. Error message: No specification for "Args": ""
1532-
DOC001: Function/method `__init__`: Potential formatting errors in docstring. Error message: No specification for "Args": "" (Note: DOC001 could trigger other unrelated violations under this function/method too. Please fix the docstring formatting first.)
1533-
DOC101: Method `ApplicationState.__init__`: Docstring contains fewer arguments than in function signature.
1534-
DOC103: Method `ApplicationState.__init__`: Docstring arguments are different from function arguments. (Or could be other formatting issues: https://jsh9.github.io/pydoclint/violation_codes.html#notes-on-doc103 ). Arguments in the function signature but not in the docstring: [deployment_state_manager: DeploymentStateManager, endpoint_state: EndpointState, logging_config: LoggingConfig, name: str].
15351531
DOC103: Method `ApplicationStateManager.deploy_app`: Docstring arguments are different from function arguments. (Or could be other formatting issues: https://jsh9.github.io/pydoclint/violation_codes.html#notes-on-doc103 ). Arguments in the function signature but not in the docstring: [deployment_args: List[Dict]]. Arguments in the docstring but not in the function signature: [deployment_args_list: ].
15361532
DOC102: Function `override_deployment_info`: Docstring contains more arguments than in function signature.
15371533
DOC103: Function `override_deployment_info`: Docstring arguments are different from function arguments. (Or could be other formatting issues: https://jsh9.github.io/pydoclint/violation_codes.html#notes-on-doc103 ). Arguments in the docstring but not in the function signature: [app_name: ].

python/ray/serve/_private/application_state.py

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from ray import cloudpickle
1414
from ray._common.utils import import_attr
1515
from ray.exceptions import RuntimeEnvSetupError
16+
from ray.serve._private.autoscaling_state import AutoscalingStateManager
1617
from ray.serve._private.build_app import BuiltApplication, build_app
1718
from ray.serve._private.common import (
1819
DeploymentID,
@@ -222,20 +223,25 @@ def __init__(
222223
self,
223224
name: str,
224225
deployment_state_manager: DeploymentStateManager,
226+
autoscaling_state_manager: AutoscalingStateManager,
225227
endpoint_state: EndpointState,
226228
logging_config: LoggingConfig,
227229
):
228230
"""
231+
Initialize an ApplicationState instance.
232+
229233
Args:
230234
name: Application name.
231-
deployment_state_manager: State manager for all deployments
232-
in the cluster.
233-
endpoint_state: State manager for endpoints in the system.
235+
deployment_state_manager: Manages the state of all deployments in the cluster.
236+
autoscaling_state_manager: Manages autoscaling decisions in the cluster.
237+
endpoint_state: Manages endpoints in the system.
238+
logging_config: Logging configuration schema.
234239
"""
235240

236241
self._name = name
237242
self._status_msg = ""
238243
self._deployment_state_manager = deployment_state_manager
244+
self._autoscaling_state_manager = autoscaling_state_manager
239245
self._endpoint_state = endpoint_state
240246
self._route_prefix: Optional[str] = None
241247
self._ingress_deployment_name: Optional[str] = None
@@ -430,6 +436,57 @@ def is_deleted(self) -> bool:
430436
"""
431437
return self._target_state.deleting and len(self._get_live_deployments()) == 0
432438

439+
def should_autoscale(self) -> bool:
440+
"""Determine if autoscaling is enabled for the application.
441+
442+
Returns:
443+
Autoscaling is enabled for the application if any of the deployments have autoscaling enabled.
444+
"""
445+
446+
return self._autoscaling_state_manager.should_autoscale_application(self._name)
447+
448+
def autoscale(self) -> bool:
449+
"""
450+
Apply the autoscaling decisions for the application.
451+
If the application has deployment-level autoscaling, it will apply the autoscaling decisions for each deployment.
452+
453+
Returns:
454+
True if there is a change to number of replicas for any deployment. False otherwise.
455+
"""
456+
target_deployments = self.target_deployments
457+
if len(target_deployments) == 0:
458+
return False
459+
460+
deployment_to_target_num_replicas: Dict[DeploymentID, int] = {}
461+
for deployment_name in target_deployments:
462+
deployment_id = DeploymentID(name=deployment_name, app_name=self._name)
463+
target_num_replicas = (
464+
self._deployment_state_manager.get_deployment_target_num_replicas(
465+
deployment_id
466+
)
467+
)
468+
if target_num_replicas is None:
469+
continue
470+
deployment_to_target_num_replicas[deployment_id] = target_num_replicas
471+
472+
if len(deployment_to_target_num_replicas) == 0:
473+
return False
474+
decisions: Dict[
475+
DeploymentID, int
476+
] = self._autoscaling_state_manager.get_decision_num_replicas(
477+
self._name, deployment_to_target_num_replicas
478+
)
479+
480+
target_state_changed = False
481+
for deployment_id, decision_num_replicas in decisions.items():
482+
target_state_changed = (
483+
self._deployment_state_manager.autoscale(
484+
deployment_id, decision_num_replicas
485+
)
486+
or target_state_changed
487+
)
488+
return target_state_changed
489+
433490
def apply_deployment_info(
434491
self,
435492
deployment_name: str,
@@ -899,11 +956,13 @@ class ApplicationStateManager:
899956
def __init__(
900957
self,
901958
deployment_state_manager: DeploymentStateManager,
959+
autoscaling_state_manager: AutoscalingStateManager,
902960
endpoint_state: EndpointState,
903961
kv_store: KVStoreBase,
904962
logging_config: LoggingConfig,
905963
):
906964
self._deployment_state_manager = deployment_state_manager
965+
self._autoscaling_state_manager = autoscaling_state_manager
907966
self._endpoint_state = endpoint_state
908967
self._kv_store = kv_store
909968
self._logging_config = logging_config
@@ -922,6 +981,7 @@ def _recover_from_checkpoint(self):
922981
app_state = ApplicationState(
923982
app_name,
924983
self._deployment_state_manager,
984+
self._autoscaling_state_manager,
925985
self._endpoint_state,
926986
self._logging_config,
927987
)
@@ -968,6 +1028,7 @@ def deploy_apps(self, name_to_deployment_args: Dict[str, List[Dict]]) -> None:
9681028
self._application_states[name] = ApplicationState(
9691029
name,
9701030
self._deployment_state_manager,
1031+
self._autoscaling_state_manager,
9711032
self._endpoint_state,
9721033
self._logging_config,
9731034
)
@@ -1018,6 +1079,7 @@ def apply_app_configs(
10181079
self._application_states[app_config.name] = ApplicationState(
10191080
app_config.name,
10201081
self._deployment_state_manager,
1082+
self._autoscaling_state_manager,
10211083
endpoint_state=self._endpoint_state,
10221084
logging_config=self._logging_config,
10231085
)
@@ -1120,6 +1182,8 @@ def update(self):
11201182
apps_to_be_deleted = []
11211183
any_target_state_changed = False
11221184
for name, app in self._application_states.items():
1185+
if app.should_autoscale():
1186+
any_target_state_changed = app.autoscale() or any_target_state_changed
11231187
ready_to_be_deleted, app_target_state_changed = app.update()
11241188
any_target_state_changed = (
11251189
any_target_state_changed or app_target_state_changed

0 commit comments

Comments
 (0)