Repository navigation
[Bugfix] Keep the offline Omni engine alive after a non-fatal request error #8450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
350b24f
5007594
f6dddd4
8084a98
3f08309
600045a
10a1e3f
406fb70
2968f1c
9c74c27
95741fb
e87a650
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ | |
| from tqdm.auto import tqdm | ||
| from vllm.logger import init_logger | ||
| from vllm.sampling_params import RequestOutputKind | ||
| from vllm.v1.engine.exceptions import EngineDeadError | ||
|
|
||
| from vllm_omni.engine.async_omni_engine import AsyncOmniEngine | ||
| from vllm_omni.engine.messages import OutputMessage | ||
|
|
@@ -95,9 +96,17 @@ def generate( | |
| if py_generator: | ||
| return self._run_generation_with_generator(prompts, sampling_params_list, use_tqdm) | ||
| return list(self._run_generation(prompts, sampling_params_list, use_tqdm)) | ||
| except EngineDeadError as e: | ||
| # Fatal: a stage or the orchestrator is gone, so the engine cannot | ||
| # serve anything else. Release the processes now. | ||
| logger.exception("[Omni] Engine died during generation: %s", e) | ||
| self.close() | ||
| raise | ||
| except Exception as e: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P1] This diff removes Evidence and suggested fixThis diff removes Evidence: Trigger: list-mode Omni.generate() consumes Suggestion: except EngineDeadError as e:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in f6dddd4. Thanks, confirmed. The generic exception handler now checks Added a CPU regression test whose Validation after the fix: 89 CPU tests passed across |
||
| # Request-scoped failure (e.g. OmniClientError -> 4xx). The in-flight | ||
| # requests were already aborted inside _run_generation; keep the | ||
| # engine alive so later generate() calls work, like AsyncOmni. | ||
| logger.exception("[Omni] Failed to run generation: %s", e) | ||
| self.close() | ||
| raise | ||
|
|
||
| def _run_generation_with_generator( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P1] This PR removes self.close() from Omni.generate()'s except Exception (omni.py:1…
Evidence and suggested fix
This PR removes self.close() from Omni.generate()'s except Exception (omni.py:105-110) and claims in-flight requests were already aborted in _run_generation. That abort (omni.py:221-225
if "active_reqs" in locals() and active_reqs) only runs after omni.py:180active_reqs = set(request_ids), which is after every add_request returns. request_states are registered at omni.py:160 before add_request at omni.py:169; a successful earlier add_request already did request_queue.sync_q.put(msg). A later prompt whose process_inputs fails (async_omni_engine.py:352-357, unchanged) therefore leaves earlier prompts in request_states and on the orchestrator queue of the now-kept-alive engine. Victim is generate([ok, bad]), not the single-prompt ErrorMessage path the new tests cover. Initialize active_reqs before the submit loop or abort leftover request_states in this except, and add that batch test.Evidence: Trigger: Omni.generate([ok, bad]) where the second engine.add_request raises in process_inputs. omni.py:105-110
except Exception as e:/logger.exception("[Omni] Failed to run generation: %s", e)/raise— this PR dropped self.close() here and comments that in-flight requests were already aborted. That abort is omni.py:221-225except Exception:/if "active_reqs" in locals() and active_reqs:/self.abort(list(active_reqs)). active_reqs is assigned only after the submit loop: omni.py:180active_reqs = set(request_ids). Each prompt is registered first: omni.py:160self.request_states[req_id] = req_statethen omni.py:169self.engine.add_request(. Unchanged by this diff, present in the PR-time tree: a successful add_request enqueues the request (async_omni_engine.py:576self.request_queue.sync_q.put(msg)) before a later prompt's process_inputs re-raises (async_omni_engine.py:352-357except Exception:...raise). Adverse effect: active_reqs is never bound so abort is skipped; the first prompt remains in request_states and on the live orchestrator queue, occupying the engine this PR now keeps up. New tests only cover single-prompt ErrorMessage after the wait loop.Suggestion: except Exception as e:
# Request-scoped failure. Abort leftovers from a submit-loop
# raise (active_reqs is assigned only after every add_request).
logger.exception("[Omni] Failed to run generation: %s", e)
leftover = list(self.request_states)
if leftover:
self.abort(leftover)
raise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in f6dddd4.
Thanks, confirmed.
_run_generation()now initializesactive_reqsbefore the try block and adds each request immediately when itsClientRequestStateis registered, before sampling-parameter preparation oradd_request(). A submission exception therefore aborts and removes all registered requests from that batch, including the failing request; prompts that were never registered are not aborted. Cleanup stays in_run_generation()so it also covers generator mode.Added a regression test for
["ok", "bad", "not submitted"], parametrized over list and generator mode. It checks that the two registered requests are aborted, the third is never submitted,request_statesis empty, the healthy engine is not shut down, and a subsequent generation succeeds. Both variants fail on the reviewed commit because no abort occurs.Validation after the fix: 89 CPU tests passed across
tests/entrypoints/test_omni_entrypoints.pyandtests/engine/test_async_omni_engine_outputs.py(vLLM 0.31.0). All applicable pre-commit checks passed except the same 9 pre-existing mypy errors; no new type errors.