@@ -723,7 +723,7 @@ def _get_replicas_to_stop(
723723 other non-serve actors on the same node. See more at
724724 https://github.com/ray-project/ray/issues/20599.
725725 """
726- replicas_to_stop : List [ ReplicaID ] = []
726+ replicas_to_stop = set ()
727727
728728 # Replicas not in running state don't have node id.
729729 # We will prioritize those first.
@@ -736,17 +736,26 @@ def _get_replicas_to_stop(
736736 pending_launching_recovering_replica
737737 ) in pending_launching_recovering_replicas :
738738 if len (replicas_to_stop ) == max_num_to_stop :
739- return set ( replicas_to_stop )
739+ return replicas_to_stop
740740 else :
741- replicas_to_stop .append (pending_launching_recovering_replica )
741+ replicas_to_stop .add (pending_launching_recovering_replica )
742742
743- node_to_running_replicas_of_target_deployment = (
744- self ._get_node_to_running_replicas (deployment_id )
745- )
746743 node_to_running_replicas_of_all_deployments = (
747744 self ._get_node_to_running_replicas ()
748745 )
749746
747+ # _running_replicas preserves insertion order (oldest → newest).
748+ # Reverse once so we have newest → oldest, then bucket by node.
749+ ordered_running_replicas = list (self ._running_replicas [deployment_id ].items ())
750+ ordered_running_replicas .reverse ()
751+ ordered_running_replicas_of_target_deployment : Dict [
752+ str , List [ReplicaID ]
753+ ] = defaultdict (list )
754+ for replica_id , replica_node_id in ordered_running_replicas :
755+ ordered_running_replicas_of_target_deployment [replica_node_id ].append (
756+ replica_id
757+ )
758+
750759 # Replicas on the head node has the lowest priority for downscaling
751760 # since we cannot relinquish the head node.
752761 def key (node_and_num_running_replicas_of_all_deployments ):
@@ -760,27 +769,16 @@ def key(node_and_num_running_replicas_of_all_deployments):
760769 for node_id , _ in sorted (
761770 node_to_running_replicas_of_all_deployments .items (), key = key
762771 ):
763- if node_id not in node_to_running_replicas_of_target_deployment :
772+ if node_id not in ordered_running_replicas_of_target_deployment :
764773 continue
765774
766- # _running_replicas dict preserves insertion order (oldest → newest).
767- # reversed(...) gives newest → oldest so the latest replica is
768- # stopped first when replicas on a node tie.
769- newest_first_replicas = [
770- rid
771- for rid , n_id in reversed (
772- list (self ._running_replicas [deployment_id ].items ())
773- )
774- if n_id == node_id
775- ]
776-
777- for running_replica in newest_first_replicas :
775+ # Newest-first list for this node.
776+ for replica_id in ordered_running_replicas_of_target_deployment [node_id ]:
777+ replicas_to_stop .add (replica_id )
778778 if len (replicas_to_stop ) == max_num_to_stop :
779- return set (replicas_to_stop )
780- if running_replica not in replicas_to_stop :
781- replicas_to_stop .append (running_replica )
779+ return replicas_to_stop
782780
783- return set ( replicas_to_stop )
781+ return replicas_to_stop
784782
785783 def _find_best_available_node (
786784 self ,
0 commit comments