[Bugfix] Avoid TCPStore port collision for co-located non-DP Ray engines (#53666)

Signed-off-by: Jeffrey Wang <jeffreywang@anyscale.com>

Jeffrey Wang committed Aug 27, 2026 at 12:58 UTC 79378fe6e87687c63ceab9815c68bf027d491868
2 files changed +32 -2
tests/distributed/test_ray_v2_executor.py
+26
@@ -128,6 +128,32 @@ def test_select_tcpstore_port_non_dp_uses_random(monkeypatch):
128 assert RayExecutorV2._select_tcpstore_port(None, master_port=29500) == 54321
129
130
131 +def test_colocated_tcpstore_ports_differ():
132 + """Two or more replicas on one host can collide on the same TCPStore port.
133 + Their ports must differ and never be a low system port.
134 + """
135 + ports = []
136 + real_select = RayExecutorV2._select_tcpstore_port
137 +
138 + def record(local_dp_rank, master_port):
139 + port = real_select(local_dp_rank, master_port)
140 + ports.append(port)
141 + return port
142 +
143 + with patch.object(RayExecutorV2, "_select_tcpstore_port", staticmethod(record)):
144 + first = RayExecutorV2(vllm_config=create_vllm_config())
145 + try:
146 + second = RayExecutorV2(vllm_config=create_vllm_config())
147 + try:
148 + assert len(ports) == 2
149 + assert min(ports) >= 1024
150 + assert ports[0] != ports[1]
151 + finally:
152 + second.shutdown()
153 + finally:
154 + first.shutdown()
155 +
156 +
157 def test_select_tcpstore_port_full_window_uses_random(monkeypatch):
158 """A fully occupied window falls back to a random port."""
159
vllm/v1/executor/ray_executor_v2.py
+6 -2
@@ -329,9 +329,13 @@ class RayExecutorV2(MultiprocExecutor):
329 # must be able to reach this address.
330 dist_ip = bundle_assignments[0]["node_ip"]
331 parallel_config = self.vllm_config.parallel_config
332 + local_dp_rank = (
333 + parallel_config.data_parallel_rank_local
334 + if parallel_config.data_parallel_size > 1
335 + else None
336 + )
337 port = self._select_tcpstore_port(
333 - parallel_config.data_parallel_rank_local,
334 - parallel_config.data_parallel_master_port,
338 + local_dp_rank, parallel_config.data_parallel_master_port
339 )
340 distributed_init_method = get_distributed_init_method(dist_ip, port)
341