Skip to content

[TRTLLM-12648][test] add disagg cancellation stress-test harness skeleton - #14375

Merged
chienchunhung merged 4 commits into
NVIDIA:mainfrom
chienchunhung:phase0-stress-test-harness
May 28, 2026
Merged

[TRTLLM-12648][test] add disagg cancellation stress-test harness skeleton#14375
chienchunhung merged 4 commits into
NVIDIA:mainfrom
chienchunhung:phase0-stress-test-harness

Conversation

@chienchunhung

@chienchunhung chienchunhung commented May 20, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Tests

    • Added comprehensive stress-test suite for disaggregated KV transfer cancellation scenarios with configuration templates and automated failure detection.
  • Documentation

    • Added operational guides for stress test setup, execution, and configuration requirements.

Review Change Stack

Summary

Skeleton + first thread body of a marathon-style (hours-running) disaggregated cancellation stress-test suite. Gates regressions of the bug class fixed by PR #13713: requests getting cancelled due to timeout or failures under high traffic.

This PR ships:

  • Harness skeleton — lifecycle (setup → start → wait_until_done → stop → collect_results), 5-thread architecture, fail-fast plumbing, StressConfig YAML parser, the C++ transceiver marathon (marathon_cpp_v1_deepseek.yaml: V1 KV cache + C++ transceiver + NIXL + DeepSeek-V3-Lite/bf16), and a symmetric Python transceiver marathon (marathon_python_v2_qwen.yaml: V2 KV cache + Python transceiver + NIXL + Qwen2.5-7B-Instruct) as a ready-to-wire template.
  • log_scanner thread body — tails each worker's stdout/stderr against configurable hard-zero regex patterns (Broken promise, Segfault, Poisoned .* cache transfer buffer, …). On a hit, trips fail-fast with a structured reason that surfaces in collect_results(). Handles block-buffered C++ writes via a carry buffer; survives missing / late-created log files.

The harness is a thin coordinating layer over the existing disagg-test infrastructure under tests/integration/defs/disaggregated/: cluster launch will delegate to setup_disagg_cluster, cancellation load generation will wrap run_cancel_stress_test, and per-worker subprocess management reuses ProcessWrapper (its log_path field is what WorkerLaunchSpec.log_path receives). Marathon YAMLs extend the existing disagg_config_cancel_stress_test*.yaml schema with a new stress_config: top-level block; the hostname / model / backend / context_servers / generation_servers keys pass through to setup_disagg_cluster unchanged.

The marathon entry point (test_disagg_cancellation_marathon) currently exercises only lifecycle plumbing + log-scan integration; content-level assertions accumulate as subsequent thread bodies land. Not registered in any test list yet — registration lands together with the load thread.

PR chain plan

Staged delivery — each follow-up adds one thread body against the harness contract locked in by this PR. Reviewable in isolation, each layer earning a new marathon assertion in the same test_disagg_cancellation_marathon entry point.

PR Adds Marathon assertion it enables
1 (this one) skeleton + log_scanner hard-zero log patterns
2 metrics_thread KV-cache utilization growth bound
3 injector_thread SIGSTOP / SIGCONT / SIGKILL+respawn; injection_events count
4 canary_thread canary error rate + token-equivalence + recovery time
5 load_thread + real setup() with save_log=True sustained load over duration_min; marathon entry point becomes a real marathon

PR 5 also flips setup_disagg_cluster to save_log=True with explicit per-worker ports — at which point the log_scanner shipped here starts catching real worker logs (today it correctly no-ops with a warning when log_path is None).

Tests added

All deterministic, GPU-free, millisecond-scale. Under tests/integration/defs/stress_test/disagg_cancel/.

  • test_disagg_cancel_stress.py — 1 lifecycle smoke (test_disagg_cancellation_marathon, parametrized on the C++ transceiver marathon) + 1 test_all_marathon_yamls_parse_and_validate that walks the configs directory and validates every marathon_*.yaml against the StressConfig schema (covers both backends, including configs not yet parametrized).
  • test_log_scanner.py — 17 unit tests covering pattern matching, block-buffered partial-line carry, multi-worker tailing, stop_event / failed_event / file-created-late lifecycle paths, misconfig (empty / invalid patterns, missing log_path, no specs), and _LogSource internal guarantees.

Out of scope (deferred to later PRs in this chain)

  • Real setup_disagg_cluster invocation (cluster launch is still a stub).
  • Remaining four thread bodies: metrics, injector, canary, load.
  • Canary reference generation tooling and stress_canary_prompts.json.
  • Registration in qa/llm_function_stress.txt for nightly / weekly CI.

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
@chienchunhung chienchunhung changed the title TRTLLM-12648][test] add disagg cancellation stress-test harness skeleton [TRTLLM-12648][test] add disagg cancellation stress-test harness skeleton May 20, 2026
…validate sanity

Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #49515 [ run ] triggered by Bot. Commit: b6ff4d9 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #49515 [ run ] completed with state SUCCESS. Commit: b6ff4d9
/LLM/main/L0_MergeRequest_PR pipeline #39148 completed with status: 'SUCCESS'

CI Report

Link to invocation

@chienchunhung
chienchunhung requested a review from pcastonguay May 21, 2026 01:48
@chienchunhung
chienchunhung marked this pull request as ready for review May 21, 2026 01:48
@chienchunhung
chienchunhung requested a review from a team as a code owner May 21, 2026 01:48
@chienchunhung
chienchunhung enabled auto-merge (squash) May 21, 2026 01:50
@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR introduces a new disaggregated KV-transfer cancellation stress-test suite. It adds documentation and module setup, configuration parsing with YAML schema validation, two concrete marathon test configurations (C++ V1 and Python V2 backends), a harness class orchestrating five worker threads with event-based coordination and log-scanner fail-fast detection, integration tests exercising the harness, and comprehensive unit/integration tests for the log-scanner component.

Changes

Disaggregated Cancellation Stress-Test Suite

Layer / File(s) Summary
Documentation and Module Foundation
tests/integration/defs/stress_test/disagg_cancel/README.md, tests/integration/defs/stress_test/disagg_cancel/__init__.py
Suite README describes the skeleton-stage implementation, file layout, usage instructions, pass/fail criteria including error log patterns, worker liveness, canary equivalence, error rates, recovery time, and KV cache growth bounds. Module docstring identifies the harness purpose and points to README for operational guidance.
Configuration Schema and Validation
tests/integration/defs/stress_test/disagg_cancel/configs/README.md, tests/integration/defs/stress_test/disagg_cancel/harness.py
StressConfig class parses and validates stress_config YAML block with fields for duration, concurrency, cancel rate, output length, and backend selection (kv_cache_manager and transceiver). WorkerLaunchSpec dataclass represents per-worker launch metadata including optional log path. Configs README documents schema inheritance, backend matrix (rejecting unsupported v2/cpp combination), and process for adding new YAML scenarios.
Marathon YAML Configuration Templates
tests/integration/defs/stress_test/disagg_cancel/configs/marathon_cpp_v1_deepseek.yaml, tests/integration/defs/stress_test/disagg_cancel/configs/marathon_python_v2_qwen.yaml
Two 120-minute marathon configurations define server topology (3+3 context/generation), KV cache and transceiver settings, stress parameters (concurrency, cancel rate, uniform input tokens), timed signal injection events (sigstop/sigkill with worker targets and respawn), canary verification (prompt rate, token equivalence, error thresholds), and hard-failure log patterns with KV cache growth cap.
Harness Lifecycle and Log-Scanning Infrastructure
tests/integration/defs/stress_test/disagg_cancel/harness.py
DisaggCancellationStressHarness class orchestrates setup/start/wait/stop lifecycle and five worker threads (load, canary, injector, log scanner, metrics) using event-based coordination (stop_event, failed_event) and atomic failure reason capture. Log-scanner utilities—_LogSource polls tailed files with chunk-splitting carry logic, _compile_patterns builds regex matchers from config—enable fail-fast on hard-zero log patterns. Stub thread bodies initialize all workers; log scanner is fully functional and polls configured sources until stop or failure.
Integration Test Entry Points
tests/integration/defs/stress_test/disagg_cancel/test_disagg_cancel_stress.py
Module defines _MARATHON_CONFIGS list and _CONFIG_DIR resolution. test_all_marathon_yamls_parse_and_validate glob-discovers all marathon_*.yaml files and validates via StressConfig.from_yaml_path and validate(). Parametrized test_disagg_cancellation_marathon constructs DisaggCancellationStressHarness, orchestrates setup/start/wait(10s)/stop in skeleton mode, asserts clean completion and presence of required result keys (canary_records, kv_utilization_samples, injection_events) with no failure reason.
Log Scanner Unit and Integration Tests
tests/integration/defs/stress_test/disagg_cancel/test_log_scanner.py
Comprehensive test coverage verifies hard-zero pattern detection across worker logs, regex metacharacter matching, benign line filtering, first-match-wins failure reason semantics, and log I/O edge cases (partial lines, chunked multiline writes). Lifecycle tests confirm clean exit on stop_event, lazy log-file discovery, and robustness to empty specs, missing log paths, or no patterns. Configuration validation tests ensure malformed regex patterns are skipped with error logging while valid patterns still trigger. _LogSource unit tests verify file polling behavior and idempotent cleanup.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding a disaggregated cancellation stress-test harness skeleton, matching the PR's primary objective.
Description check ✅ Passed The PR description is comprehensive and follows the template structure with detailed Summary, Test Coverage, and PR Checklist sections clearly addressing requirements and scope.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (5)
tests/integration/defs/stress_test/disagg_cancel/test_log_scanner.py (2)

455-455: ⚡ Quick win

Replace the type: ignore with a narrow non-None guard.

This suppresses type checking where a direct assertion can make the invariant explicit and preserve checker value.

Proposed change
 def test_log_source_poll_returns_false_when_file_absent(tmp_path: Path):
     spec = _make_spec("ctx", 0, tmp_path / "missing.log")
-    src = _LogSource(spec=spec, path=Path(spec.log_path))  # type: ignore[arg-type]
+    assert spec.log_path is not None
+    src = _LogSource(spec=spec, path=Path(spec.log_path))
As per coding guidelines, “avoid using `# type: ignore` annotations unless absolutely necessary.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/defs/stress_test/disagg_cancel/test_log_scanner.py` at line
455, The construction of _LogSource uses a broad "# type: ignore[arg-type]" to
silence a possibly None log_path; instead add an explicit non-None guard for
spec.log_path (e.g., assert or raise) before building Path and creating
_LogSource so the type checker can see the invariant; specifically, check
spec.log_path is not None (or raise a ValueError) just above the _LogSource(...)
call so you can call Path(spec.log_path) without the type: ignore.

86-87: ⚡ Quick win

Add an explicit return type to the fixture.

harness_with_two_workers is missing a return type annotation; adding it keeps typing expectations consistent and clearer for fixture consumers.

Proposed change
 `@pytest.fixture`
-def harness_with_two_workers(tmp_path: Path):
+def harness_with_two_workers(
+    tmp_path: Path,
+) -> tuple[DisaggCancellationStressHarness, Path, Path]:
As per coding guidelines, “always annotate Python functions with return types (use `None` if no return); make return type explicit.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/defs/stress_test/disagg_cancel/test_log_scanner.py` around
lines 86 - 87, Add an explicit return type annotation to the pytest fixture
function harness_with_two_workers: annotate the function with the concrete type
it yields (or a generator type) instead of leaving it untyped — e.g. change the
signature to include -> Generator[HarnessType, None, None] or -> HarnessType (or
the actual fixture class/type used in tests) so the fixture's return/yield type
is explicit and consistent with typing guidelines.
tests/integration/defs/stress_test/disagg_cancel/test_disagg_cancel_stress.py (1)

59-60: Register this new integration test in CI/QA test lists before relying on it.

This adds a new integration test under tests/integration/defs/; please add a follow-up entry in the authoritative CI test-db list and the matching QA schedule list (likely tests/integration/test_lists/qa/llm_function_core.txt for single-node functional coverage), otherwise regressions here may not be exercised regularly.

As per coding guidelines, “If the change adds or materially alters an integration test under tests/integration/defs/, call out whether an entry is needed under tests/integration/test_lists/qa/.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@tests/integration/defs/stress_test/disagg_cancel/test_disagg_cancel_stress.py`
around lines 59 - 60, This new integration test function
test_disagg_cancellation_marathon (parametrized by _MARATHON_CONFIGS) must be
registered with our CI/QA test lists: add an entry for this test to the
authoritative CI test-db and also add it to the single-node functional QA
schedule list (the QA list that covers LLM function core tests) so it runs
regularly; ensure the test identifier matches test_disagg_cancellation_marathon
and include any required tags/labels used by the test-runner so it is picked up
by CI/QA automation.
tests/integration/defs/stress_test/disagg_cancel/README.md (1)

32-42: 💤 Low value

Specify language for fenced code block.

The directory tree at lines 32-42 should specify a language identifier (e.g., text or leave empty) to satisfy markdown linters.

📝 Proposed fix
-```
+```text
 tests/integration/defs/stress_test/disagg_cancel/
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/defs/stress_test/disagg_cancel/README.md` around lines 32 -
42, The fenced code block showing the directory tree in README.md lacks a
language tag required by markdown linters; update the block (the triple-backtick
block that contains the tree under
tests/integration/defs/stress_test/disagg_cancel/) to include a language
identifier such as text (e.g., replace ``` with ```text) so the tree block is
properly annotated.
tests/integration/defs/stress_test/disagg_cancel/harness.py (1)

92-94: ⚡ Quick win

Consider adding field-specific error context for type coercion failures.

If a YAML field contains invalid data (e.g., duration_min: "not-a-number"), the current code will raise a generic ValueError from int() without indicating which field caused the failure. Wrapping the coercion in a try-except that re-raises with field context would improve the debugging experience.

♻️ Proposed enhancement
 for name, coerce in _STRESS_CONFIG_COERCERS.items():
     if name in sc:
-        kwargs[name] = coerce(sc[name])
+        try:
+            kwargs[name] = coerce(sc[name])
+        except (ValueError, TypeError) as exc:
+            raise ValueError(
+                f"Invalid value for stress_config.{name}: {sc[name]!r} "
+                f"(expected {coerce.__name__})"
+            ) from exc
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/defs/stress_test/disagg_cancel/harness.py` around lines 92
- 94, Wrap each call to the coercer for entries in _STRESS_CONFIG_COERCERS in a
try/except to catch conversion errors and re-raise a new ValueError that
includes the field name (the loop variable name), the offending raw value
(sc[name]) and the original exception message; ensure you reference the same
variables (name, coerce, sc, kwargs) so the new error gives clear field-specific
context while preserving or chaining the original exception.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/integration/defs/stress_test/disagg_cancel/harness.py`:
- Around line 92-94: Wrap each call to the coercer for entries in
_STRESS_CONFIG_COERCERS in a try/except to catch conversion errors and re-raise
a new ValueError that includes the field name (the loop variable name), the
offending raw value (sc[name]) and the original exception message; ensure you
reference the same variables (name, coerce, sc, kwargs) so the new error gives
clear field-specific context while preserving or chaining the original
exception.

In `@tests/integration/defs/stress_test/disagg_cancel/README.md`:
- Around line 32-42: The fenced code block showing the directory tree in
README.md lacks a language tag required by markdown linters; update the block
(the triple-backtick block that contains the tree under
tests/integration/defs/stress_test/disagg_cancel/) to include a language
identifier such as text (e.g., replace ``` with ```text) so the tree block is
properly annotated.

In
`@tests/integration/defs/stress_test/disagg_cancel/test_disagg_cancel_stress.py`:
- Around line 59-60: This new integration test function
test_disagg_cancellation_marathon (parametrized by _MARATHON_CONFIGS) must be
registered with our CI/QA test lists: add an entry for this test to the
authoritative CI test-db and also add it to the single-node functional QA
schedule list (the QA list that covers LLM function core tests) so it runs
regularly; ensure the test identifier matches test_disagg_cancellation_marathon
and include any required tags/labels used by the test-runner so it is picked up
by CI/QA automation.

In `@tests/integration/defs/stress_test/disagg_cancel/test_log_scanner.py`:
- Line 455: The construction of _LogSource uses a broad "# type:
ignore[arg-type]" to silence a possibly None log_path; instead add an explicit
non-None guard for spec.log_path (e.g., assert or raise) before building Path
and creating _LogSource so the type checker can see the invariant; specifically,
check spec.log_path is not None (or raise a ValueError) just above the
_LogSource(...) call so you can call Path(spec.log_path) without the type:
ignore.
- Around line 86-87: Add an explicit return type annotation to the pytest
fixture function harness_with_two_workers: annotate the function with the
concrete type it yields (or a generator type) instead of leaving it untyped —
e.g. change the signature to include -> Generator[HarnessType, None, None] or ->
HarnessType (or the actual fixture class/type used in tests) so the fixture's
return/yield type is explicit and consistent with typing guidelines.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 114aaa5e-fb57-4401-b5d5-58405ae1b6b9

📥 Commits

Reviewing files that changed from the base of the PR and between 8ba76f4 and b6ff4d9.

📒 Files selected for processing (8)
  • tests/integration/defs/stress_test/disagg_cancel/README.md
  • tests/integration/defs/stress_test/disagg_cancel/__init__.py
  • tests/integration/defs/stress_test/disagg_cancel/configs/README.md
  • tests/integration/defs/stress_test/disagg_cancel/configs/marathon_cpp_v1_deepseek.yaml
  • tests/integration/defs/stress_test/disagg_cancel/configs/marathon_python_v2_qwen.yaml
  • tests/integration/defs/stress_test/disagg_cancel/harness.py
  • tests/integration/defs/stress_test/disagg_cancel/test_disagg_cancel_stress.py
  • tests/integration/defs/stress_test/disagg_cancel/test_log_scanner.py

Comment thread tests/integration/defs/stress_test/disagg_cancel/harness.py Outdated
Comment thread tests/integration/defs/stress_test/disagg_cancel/harness.py Outdated
Comment thread tests/integration/defs/stress_test/disagg_cancel/harness.py Outdated
…tress harness

Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@chienchunhung
chienchunhung requested a review from pcastonguay May 22, 2026 00:08
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #49791 [ run ] triggered by Bot. Commit: 6b7b217 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #49791 [ run ] completed with state SUCCESS. Commit: 6b7b217
/LLM/main/L0_MergeRequest_PR pipeline #39382 completed with status: 'SUCCESS'

CI Report

Link to invocation

Comment thread tests/integration/defs/stress_test/disagg_cancel/README.md
@chienchunhung
chienchunhung merged commit 1a52920 into NVIDIA:main May 28, 2026
7 checks passed
bmarimuthu-nv pushed a commit to nv-auto-deploy/TensorRT-LLM that referenced this pull request May 28, 2026
…eton (NVIDIA#14375)

Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
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.

5 participants