Skip to content

refactor e2e tests with concurrent polling and add Buildkite CI config - #250

Merged
fangyuchu merged 1 commit into
feature/ft-simplifyfrom
fyc-dev
Jul 21, 2026
Merged

fangyuchu merged 1 commit into
feature/ft-simplifyfrom
fyc-dev

Conversation

@fangyuchu

@fangyuchu fangyuchu commented Jul 21, 2026 •

Copy link
Copy Markdown
Owner

PLEASE FILL IN THE PR DESCRIPTION HERE ENSURING ALL CHECKLIST ITEMS (AT THE BOTTOM) HAVE BEEN CONSIDERED.

Purpose

Test Plan

python -m pytest tests/v1/fault_tolerance/test_fault_tolerance_e2e.py -v -s

Test Result

通过

Essential Elements of an Effective PR Description Checklist
  • The purpose of the PR, such as "Fix some issue (link existing issues this PR will resolve)".
  • The test plan, such as providing test command.
  • The test results, such as pasting the results comparison before and after, or e2e results
  • (Optional) The necessary documentation update, such as updating supported_models.md and examples for a new model.
  • (Optional) Release notes update. If your change is user facing, please update the release notes draft in the Google Doc.

BEFORE SUBMITTING, PLEASE READ https://docs.vllm.ai/en/latest/contributing (anything written below this line will be removed by GitHub Actions)

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a Buildkite pipeline step for fault tolerance E2E tests on H100 GPUs and refactors the fault tolerance tests to support concurrent polling and execution across multiple servers. The review feedback highlights that the new _wait_for_engines helper still polls servers sequentially, which could block the loop for up to 10 seconds if a server is unresponsive. The reviewer suggests using a ThreadPoolExecutor to poll the servers concurrently to avoid test flakiness.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +214 to +227
results: dict[int, dict[str, Any]] = {}
pending = dict(enumerate(servers))
start = time.time()
while time.time() - start < deadline_s:
with contextlib.suppress(Exception):
for engine in _get_ft_status(server)["engines"]:
if predicate(engine):
return engine
time.sleep(1.0)
return None


def _wait_for_status(server, statuses, deadline_s: int = FAULT_DETECTION_DEADLINE_S):
"""Poll until an engine reports one of ``statuses`` (a set of status strings)."""
return _poll_status(server, deadline_s, lambda e: e["status"] in statuses)
while pending and time.time() - start < deadline_s:
for i, server in list(pending.items()):
with contextlib.suppress(Exception):
for engine_status in _get_ft_status(server)["engines"]:
if engine_status.get(match_key) in match_values:
results[i] = engine_status
del pending[i]
break
if pending:
time.sleep(1.0)
return [results.get(i) for i in range(len(servers))]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current implementation of _wait_for_engines polls the servers sequentially. Since _get_ft_status has a 10-second timeout, any unresponsive or slow server will block the entire polling loop for up to 10 seconds, preventing other servers from being polled. This can lead to test flakiness or timeouts, and defeats the PR's goal of "concurrent polling".

We should poll the pending servers concurrently using a ThreadPoolExecutor (similar to _in_parallel).

    results: dict[int, dict[str, Any]] = {}
    pending = dict(enumerate(servers))
    start = time.time()
    with ThreadPoolExecutor(max_workers=max(1, len(servers))) as ex:
        while pending and time.time() - start < deadline_s:
            items = list(pending.items())

            def poll(item):
                idx, server = item
                try:
                    for engine_status in _get_ft_status(server)["engines"]:
                        if engine_status.get(match_key) in match_values:
                            return idx, engine_status
                except Exception:
                    pass
                return idx, None

            for idx, engine_status in ex.map(poll, items):
                if engine_status is not None:
                    results[idx] = engine_status
                    del pending[idx]
            if pending:
                time.sleep(1.0)
    return [results.get(i) for i in range(len(servers))]

@fangyuchu
fangyuchu merged this pull request into feature/ft-simplify Jul 21, 2026
2 of 6 checks passed
fangyuchu added a commit that referenced this pull request Jul 23, 2026
zWaNg3 added a commit to zWaNg3/vllm that referenced this pull request Jul 25, 2026
…ft-simplify

This squashes the following commits into one:
- Fault Tolerance Framework (fangyuchu#229)
- unify param name for nixl and deepep and destroy old cpu_group in retry (fangyuchu#230)
- Surface exception to status
- change status report mode from pull to push
- simplify fault tolerance config args
- use existing get_all2all_manager implementation
- support tp>1 (fangyuchu#241)
- Enhance the pass of fault tolerance results (fangyuchu#242)
- clean states for model runner v2
- add support for fault detection through mask for model runner v2
- [FT] validate single API server, fix clean_buffers ordering and worker state cleanup
- [FT] make apply endpoint async and gate recovery by engine status
- add e2e test for fault tolerance
- add e2e test for retry recovery
- refactor e2e tests with concurrent polling and add Buildkite CI config (fangyuchu#250)
- set cpu timeout to default value of nixl-ep in test (fangyuchu#251)

Co-Authored-By: Claude <noreply@anthropic.com>
fangyuchu added a commit that referenced this pull request Jul 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant