Skip to content

Commit a98eab7

Browse files
Added tests for cross app chains being preserved during shutdown
Signed-off-by: YashwanthRanjanSingaravel <yashwanth.ranjansingaravel@anyscale.com>
1 parent bf401c8 commit a98eab7

1 file changed

Lines changed: 97 additions & 0 deletions

File tree

python/ray/serve/tests/unit/test_deployment_state.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10309,6 +10309,20 @@ def test_multi_app_independent(self, mock_deployment_state_manager):
1030910309
assert set(tiers[0]) == {a1, a2}
1031010310
assert set(tiers[1]) == {b1, b2}
1031110311

10312+
def test_cross_app_chain(self, mock_deployment_state_manager):
10313+
"""A caller in app1 orders before its callee in app2."""
10314+
create_dsm, _, _, _ = mock_deployment_state_manager
10315+
dsm: DeploymentStateManager = create_dsm()
10316+
ingress1 = _dep("ingress", app="app1")
10317+
ingress2 = _dep("ingress", app="app2")
10318+
leaf2 = _dep("leaf", app="app2")
10319+
_deploy_running(dsm, ingress1, outbound=[ingress2])
10320+
_deploy_running(dsm, ingress2, outbound=[leaf2])
10321+
_deploy_running(dsm, leaf2, outbound=[])
10322+
10323+
tiers = dsm._shutdown_deletion_tiers()
10324+
assert tiers == [[ingress1], [ingress2], [leaf2]]
10325+
1031210326
def test_no_deployments(self, mock_deployment_state_manager):
1031310327
"""No deployments produces no tiers."""
1031410328
create_dsm, _, _, _ = mock_deployment_state_manager
@@ -10396,6 +10410,21 @@ def test_multi_app_independent(self, mock_deployment_state_manager):
1039610410
assert order.index(b1) > order.index(a1)
1039710411
assert order.index(b2) > order.index(a2)
1039810412

10413+
def test_cross_app_chain_delete_order(self, mock_deployment_state_manager):
10414+
"""App 1 calling App 2 tears the app1 caller down before the app2 callee."""
10415+
create_dsm, _, _, _ = mock_deployment_state_manager
10416+
dsm: DeploymentStateManager = create_dsm()
10417+
ingress1 = _dep("ingress", app="app1")
10418+
ingress2 = _dep("ingress", app="app2")
10419+
leaf2 = _dep("leaf", app="app2")
10420+
_deploy_running(dsm, ingress1, outbound=[ingress2])
10421+
_deploy_running(dsm, ingress2, outbound=[leaf2])
10422+
_deploy_running(dsm, leaf2, outbound=[])
10423+
10424+
order = _run_shutdown_to_completion(dsm)
10425+
assert dsm.is_ready_for_shutdown()
10426+
assert order == [ingress1, ingress2, leaf2]
10427+
1039910428
def test_wedged_tier_still_completes(self, mock_deployment_state_manager):
1040010429
"""A tier that never drains is force-advanced past after the timeout."""
1040110430
create_dsm, timer, _, _ = mock_deployment_state_manager
@@ -10488,5 +10517,73 @@ def test_shutdown_tiers_survive_application_reconcile(mock_deployment_state_mana
1048810517
assert dsm.is_ready_for_shutdown()
1048910518

1049010519

10520+
def test_cross_app_shutdown_survives_application_reconcile(
10521+
mock_deployment_state_manager,
10522+
):
10523+
"""Cross app tier order holds when each app delete wipes its target list."""
10524+
create_dsm, _, _, autoscaling_state_manager = mock_deployment_state_manager
10525+
dsm: DeploymentStateManager = create_dsm()
10526+
10527+
def _make_app(name):
10528+
return ApplicationState(
10529+
name=name,
10530+
deployment_state_manager=dsm,
10531+
autoscaling_state_manager=autoscaling_state_manager,
10532+
endpoint_state=EndpointState(MockKVStore(), Mock()),
10533+
logging_config=LoggingConfig(),
10534+
external_scaler_enabled=False,
10535+
)
10536+
10537+
app1 = _make_app("app1")
10538+
app2 = _make_app("app2")
10539+
info1, _ = deployment_info(num_replicas=1)
10540+
info2, _ = deployment_info(num_replicas=1)
10541+
app1.deploy_app({"ingress": info1}, external_scaler_enabled=False)
10542+
app2.deploy_app({"backend": info2}, external_scaler_enabled=False)
10543+
app1.update()
10544+
app2.update()
10545+
10546+
ingress = _dep("ingress", app="app1")
10547+
backend = _dep("backend", app="app2")
10548+
ds_ingress = dsm._get_deployment_state_for_testing(ingress)
10549+
ds_backend = dsm._get_deployment_state_for_testing(backend)
10550+
10551+
dsm.update()
10552+
for r in ds_ingress._replicas.get([ReplicaState.STARTING]):
10553+
r._actor.set_ready()
10554+
for r in ds_backend._replicas.get([ReplicaState.STARTING]):
10555+
r._actor.set_ready()
10556+
dsm.update()
10557+
for r in ds_ingress._replicas.get([ReplicaState.RUNNING]):
10558+
r._actor._outbound_deployments = [backend]
10559+
for r in ds_backend._replicas.get([ReplicaState.RUNNING]):
10560+
r._actor._outbound_deployments = []
10561+
10562+
dsm.shutdown()
10563+
assert ds_ingress._target_state.deleting
10564+
assert not ds_backend._target_state.deleting
10565+
10566+
app1.delete()
10567+
app2.delete()
10568+
app1.update()
10569+
app2.update()
10570+
assert not ds_backend._target_state.deleting
10571+
10572+
dsm.update()
10573+
for r in ds_ingress._replicas.get([ReplicaState.STOPPING]):
10574+
r._actor.set_done_stopping()
10575+
dsm.update()
10576+
dsm.shutdown()
10577+
app1.update()
10578+
app2.update()
10579+
assert ds_backend._target_state.deleting
10580+
10581+
dsm.update()
10582+
for r in ds_backend._replicas.get([ReplicaState.STOPPING]):
10583+
r._actor.set_done_stopping()
10584+
dsm.update()
10585+
assert dsm.is_ready_for_shutdown()
10586+
10587+
1049110588
if __name__ == "__main__":
1049210589
sys.exit(pytest.main(["-v", "-s", __file__]))

0 commit comments

Comments
 (0)