From 10701e18389fe282ca8c2510cd2022a76a9dad2a Mon Sep 17 00:00:00 2001 From: heyuanliu-intel <90166842+heyuanliu-intel@users.noreply.github.com> Date: Fri, 4 Sep 2026 16:45:17 +0800 Subject: [PATCH] [Bugfix] Release diffusion worker RPC results on ranks that do not reply (#6989) Signed-off-by: heyuanliu-intel --- .../test_multiproc_engine_concurrency.py | 44 +++++++++++++++++++ .../diffusion/worker/diffusion_worker.py | 8 ++++ 2 files changed, 52 insertions(+) diff --git a/tests/diffusion/test_multiproc_engine_concurrency.py b/tests/diffusion/test_multiproc_engine_concurrency.py index 855f38c4a..9bd7a3e8f 100644 --- a/tests/diffusion/test_multiproc_engine_concurrency.py +++ b/tests/diffusion/test_multiproc_engine_concurrency.py @@ -848,6 +848,50 @@ class TestWorkerProcRpcRankStatus: gc_collect.assert_called_once_with() mock_platform.empty_cache.assert_called_once_with() + def test_execute_rpc_drops_the_result_on_ranks_that_will_not_reply(self): + """A rank that will not reply must not hand its output back. + + The busy loop binds the returned object to a local that outlives the + RPC, so a device-resident result -- for diffusion, a whole decoded + video -- would occupy accelerator memory on every non-reply rank until + the next request replaces it. + """ + proc = self._make_worker_proc() + payload = {"frames": object()} + proc.worker.execute_method = lambda *args, **kwargs: payload + + result, should_reply = proc._execute_rpc( + { + "method": "execute_model", + "args": (), + "kwargs": {}, + "output_rank": 1, + "exec_all_ranks": True, + } + ) + + assert should_reply is False + assert result is None, "a non-reply rank must not keep the output alive" + + def test_execute_rpc_still_returns_the_result_on_the_replying_rank(self): + """The rank that owns the reply keeps returning the same object.""" + proc = self._make_worker_proc() + payload = {"frames": object()} + proc.worker.execute_method = lambda *args, **kwargs: payload + + result, should_reply = proc._execute_rpc( + { + "method": "execute_model", + "args": (), + "kwargs": {}, + "output_rank": 0, + "exec_all_ranks": True, + } + ) + + assert should_reply is True + assert result is payload + def test_execute_rpc_rejects_collect_rank_status_without_all_ranks(self): proc = self._make_worker_proc() diff --git a/vllm_omni/diffusion/worker/diffusion_worker.py b/vllm_omni/diffusion/worker/diffusion_worker.py index 033848008..b65498d75 100644 --- a/vllm_omni/diffusion/worker/diffusion_worker.py +++ b/vllm_omni/diffusion/worker/diffusion_worker.py @@ -1327,6 +1327,14 @@ class WorkerProc: if isinstance(result, dict) and wave_id is not None: result["wave_id"] = wave_id + if not should_reply: + # A rank that will not reply must not hand the result back: the busy + # loop binds it to a local that stays alive until the next request + # overwrites it, so a device-resident output -- for diffusion, an + # entire decoded video -- would occupy accelerator memory for the + # whole idle period on every rank that did not produce the reply. + # The `collect_rank_status` branch above already returns None here. + return None, False return result, should_reply def recv_message(self) -> Any: