[Feature][MiniMax-H3] Support diffusion continuous batching (#5810)

Signed-off-by: princepride <wangzhipeng628@gmail.com>
Signed-off-by: lishunyang12 <lishunyang12@163.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: lishunyang12 <lishunyang12@163.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
authored and GitHub committed 2026-08-24 21:08:53 +08:00
1 parent aa69acbd09
commit d150a4fde7
15 files changed
+1834 -140

No files matched your search

@@ -47,6 +47,7 @@ from vllm_omni.diffusion.worker.diffusion_worker import DiffusionWorker
from vllm_omni.diffusion.worker.input_batch import InputBatch
from vllm_omni.diffusion.worker.utils import RunnerOutput, StepRequestState
from vllm_omni.engine.async_omni_engine import AsyncOmniEngine
from vllm_omni.errors import OmniClientError
from vllm_omni.inputs.data import OmniDiffusionSamplingParams
from vllm_omni.platforms import current_omni_platform
@@ -102,6 +103,22 @@ class _StepPipeline:
return DiffusionOutput(output=torch.tensor([state.step_index], dtype=torch.float32))
class _PerRequestErrorStepPipeline(_StepPipeline):
def prepare_encode(self, state, **kwargs):
if state.prompt == "fail-prepare":
raise OmniClientError(
"invalid request input",
status_code=422,
error_type="UnprocessableEntityError",
)
return super().prepare_encode(state, **kwargs)
def denoise_step(self, input_batch, **kwargs):
del kwargs
self.denoise_calls += 1
return torch.ones_like(input_batch.latents)
class _ProfilingStepPipeline(_StepPipeline):
enable_diffusion_pipeline_profiler = True
@@ -697,6 +714,72 @@ class TestRunner:
result = DiffusionModelRunner.execute_stepwise(runner, scheduler_output)
assert len(result) == 2
def test_prepare_error_isolated_from_healthy_request(self, monkeypatch):
runner = _make_runner()
runner.pipeline = _PerRequestErrorStepPipeline()
bad_req = _make_step_request()
bad_req.request_id = "req-bad"
bad_req.prompt = "fail-prepare"
good_req = _make_step_request()
good_req.request_id = "req-good"
good_req.prompt = "valid"
monkeypatch.setattr(model_runner_module, "set_forward_context", _noop_forward_context)
result = DiffusionModelRunner.execute_stepwise(
runner,
_make_batch_scheduler_output([bad_req, good_req]),
)
bad_output = result.get_request_output("req-bad")
assert bad_output.finished is True
assert bad_output.result is not None
assert bad_output.result.error == "invalid request input"
assert bad_output.result.error_status_code == 422
assert bad_output.result.error_type == "UnprocessableEntityError"
good_output = result.get_request_output("req-good")
assert good_output.finished is False
assert good_output.step_index == 1
assert good_output.result is None
assert set(runner.state_cache) == {"req-good"}
assert runner.pipeline.denoise_calls == 1
assert runner.pipeline.scheduler_calls == 1
def test_prepare_error_on_other_rank_is_isolated_via_all_reduce(self, monkeypatch):
"""P1-B: rank-0-only pipeline work (e.g. H3 reference-video prep)
can raise on rank 0 while non-zero ranks return cleanly and then hang
on a downstream ``dist.broadcast``. Beyond the pipeline-side guard,
the runner all-reduces a per-request failure flag across the DiT
group so a rank that ``prepare_encode`` returned cleanly on still
skips the request and does not enter the denoise step batch.
"""
runner = _make_runner()
runner.pipeline = _StepPipeline() # locally always succeeds
monkeypatch.setattr(model_runner_module, "set_forward_context", _noop_forward_context)
# Simulate a peer DiT rank having reported failure. We patch the
# helper directly (rather than ``torch.distributed`` broadly) because
# ``execute_stepwise`` also queries ``torch.distributed.get_rank``.
monkeypatch.setattr(
model_runner_module,
"_dit_any_rank_failed",
lambda local_failed: True,
)
req = _make_step_request(num_inference_steps=1)
result = DiffusionModelRunner.execute_stepwise(
runner,
_make_scheduler_output(req),
)
output = result.get_request_output("req-1")
assert output.finished is True
assert output.result is not None
assert output.result.error is not None
assert "another DiT rank" in output.result.error
# A rank that skipped the request must not have driven a denoise step.
assert runner.pipeline.denoise_calls == 0
assert runner.state_cache == {}
def test_receives_kv_payload_before_prepare_encode(self, monkeypatch):
runner = _make_runner()
captured: dict[str, object] = {}