fix(generation): report no OpenAI server as an empty list - #3993
Open
yupengtang wants to merge 1 commit into
Open
fix(generation): report no OpenAI server as an empty list#3993yupengtang wants to merge 1 commit into
yupengtang wants to merge 1 commit into
Conversation
The four generation backends disagreed on what `dp_openai_server_base_urls` holds when there is no HTTP server to report. Megatron returned `[]`; vLLM, TRT-LLM and Dynamo returned a list of `None`s. The placeholder does not stand for anything -- in those branches no server exists, so the length carries no information -- but it does make the value lie to a plain truth test, since `[None]` is truthy. Callers had to know that and write `if not any(urls)` instead of `if not urls`, and a sync run printed `Reserved 1 vLLM server URLs: [None]`. Match Megatron, which already filters its Nones out, and narrow the type to `list[str]`. `NemoGymConfig.base_urls` and `spinup_nemo_gym_actor` already declare `list[str]`, so the producers now match what the consumers ask for. vLLM needed more than swapping the sentinel. A worker leaves `base_url` unset unless `expose_http_server` started a server, so an async engine without one answered `[None] * dp_size` from the workers themselves, not from the guarded branch. Both `_report_dp_openai_server_base_urls` and `_collect_reserved_urls` now drop those, which is the case the guard alone never covered. No caller changes needed: `_shard_base_urls` already collapses an all-None list to None and does the same with an empty one, `_maybe_start_generation_router` filters falsy entries before its own emptiness check, and NeMo-Gym is reachable only behind the `should_expose_http_server` assert, so the no-server list never gets there. Nothing reads the length in the no-server case. The redundant `any(...)` guards stay as they are. Signed-off-by: Yupeng Tang <85978465+yupengtang@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do ?
Makes all four generation backends report "no OpenAI server" the same way — an empty list — and narrows
dp_openai_server_base_urlstolist[str].Megatron already returns
[]and filters itsNones out. vLLM, TRT-LLM and Dynamo returned a list ofNones instead. As #3977 says, the placeholder does not stand for anything: in those branches there is no server at all, so the length carries no information, but[None]is truthy, so "we have URLs" reads as true when there are none.Changed to match Megatron:
[None][][None][][None] * dp_size[][None][]NemoGymConfig.base_urlsandspinup_nemo_gym_actoralready declarelist[str], so this makes the producers match what the consumers were asking for rather than widening anything.One case the issue does not list
vLLM needed more than swapping the sentinel. A worker leaves
base_urlunset unlessexpose_http_serverstarted a server (vllm_worker_async.py:104assignsNone,:206-210only sets it under that flag), andget_reserved_urlreturnsNoneunless a socket was reserved under the same flag. Soasync_engine: truewithexpose_http_server: falseproduced[None] * dp_sizefrom the workers themselves, never reaching the guarded branch — a longer, still-truthy version of the same problem. Both_report_dp_openai_server_base_urlsand_collect_reserved_urlsnow drop those, which is why they filter rather than only returning[]early.Issues
Closes #3977.
Usage
No config or API change.
if not urlsis now a correct emptiness test on every backend.Before your PR is "Ready for review"
Pre checks:
Additional Information
Callers
I went through every reader before changing the producers. None needed edits, and none reads the length in the no-server case:
_shard_base_urls(setup.py:777) collapses an all-Nonelist toNoneviaif not any(urls); an empty list takes the same branch._maybe_start_generation_routerfilters falsy entries intobackend_urlsand raises when that is empty, so[None]and[]already produced the identical error.should_expose_http_serverassert innemo_rl/environments/nemo_gym.py, so the no-server list never gets there.MegatronGeneration.verify_served_addressonly ever saw Megatron's list, which was already[].len()call,grpo.py:1550, is a print on the deferred vLLM path. It now saysReserved 0 vLLM server URLs: []instead ofReserved 1 vLLM server URLs: [None], which is the symptom the issue calls out.Per the issue I left the now-redundant
any(...)guards alone — they stay correct either way and are cleaner to remove separately.Tests
Five added, plus the existing Dynamo assertion at
test_dynamo_generation.py:167updated from[None]to[].tests/unit/models/generation/test_vllm_generation.py:test_sync_engine_reports_no_openai_server_urlstest_async_engine_without_http_server_reports_no_urls— the case above, workers answering allNonestest_async_engine_with_http_server_reports_served_urls— guards the happy path against over-filteringtests/unit/models/generation/trtllm/test_trtllm_generation.py:test_no_http_server_reports_an_empty_url_listtest_exposed_http_server_reports_served_addressesReverting each backend to its pre-fix version, the no-server tests fail and the served-address tests still pass:
With the change, the touched suites and the consumer suites pass:
CPU only — I don't have a GPU box, so the vLLM/TRT-LLM tests that need a real engine and the functional suite did not run here. The
--trtllm-onlyselection needed a stubtensorrt_llmlocally to get past the conftest gate; the two tests themselves only use_bare_generationand a mocked worker group.ruff 0.9.9check, import sort and format are clean on all seven files.