Skip to content

fix(router): use independent P/D policies in gRPC PD selection - #2035

Merged
slin1237 merged 7 commits into
smg-project:mainfrom
OftenDream:fix/pd-round-robin-independent-policies
Aug 4, 2026
Merged

fix(router): use independent P/D policies in gRPC PD selection#2035
slin1237 merged 7 commits into
smg-project:mainfrom
OftenDream:fix/pd-round-robin-independent-policies

Conversation

@OftenDream

Copy link
Copy Markdown
Contributor

Summary

  • gRPC PD select_pd_pair previously shared one policy instance for prefill and decode, so stateful policies like round_robin advanced the same counter twice per request and each role only hit every other worker.
  • Use independent get_prefill_policy / get_decode_policy (same approach as the EPD path).
  • Add a regression test showing shared vs independent round-robin coverage across two pools.

Test plan

  • Unit test test_independent_policies_cover_all_workers_across_two_pools
  • Live PD 4P4D press: 40 requests with --prefill-policy/--decode-policy round_robin → each of 4 prefill and 4 decode workers got equal traffic

Co-authored-by: longcat-ia-team 312376714+longcat-ia-team@users.noreply.github.com

Made with Cursor

Sharing one round_robin counter across prefill and decode made each
role only see every other worker index.

Signed-off-by: yangxurui <yangxurui@meituan.com>
Co-authored-by: longcat-ia-team <312376714+longcat-ia-team@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions github-actions Bot added grpc gRPC client and router changes model-gateway Model gateway crate changes labels Aug 3, 2026
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5c9b968a-b5c6-4c49-937f-929a7f51ec93

📥 Commits

Reviewing files that changed from the base of the PR and between 9e2b38c and dda4843.

📒 Files selected for processing (2)
  • model_gateway/src/policies/round_robin.rs
  • model_gateway/src/routers/grpc/common/stages/worker_selection.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • model_gateway/src/policies/round_robin.rs
  • model_gateway/src/routers/grpc/common/stages/worker_selection.rs

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved PD worker selection by independently balancing prefill and decode workers.
    • Updated selection metrics to accurately reflect the policy used for each worker type.
    • Improved round-robin distribution across multiple worker pools for more even workload balancing.
    • Added coverage to verify consistent and independent worker distribution across prefill and decode pools.

Walkthrough

The change separates prefill and decode worker-selection policies in PD routing. It updates selection metrics to use each leg’s policy and adds regression coverage for independent round-robin state across worker pools.

Changes

PD worker selection

Layer / File(s) Summary
Separate PD policy wiring
model_gateway/src/routers/grpc/common/stages/worker_selection.rs
select_pd_pair retrieves independent prefill and decode policies. Each selection metric records the policy used for its worker selection. Tests verify even distribution across both worker pools.
Round-robin state regression coverage
model_gateway/src/policies/round_robin.rs
A test compares shared and independent RoundRobinPolicy instances across two four-worker pools and verifies their selection distributions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: catherinesue, key4ng

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% 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 states the main fix: gRPC PD selection now uses independent prefill and decode policies.
Description check ✅ Passed The description accurately explains the shared-policy defect, the independent-policy fix, and the regression tests.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@model_gateway/src/policies/round_robin.rs`:
- Around line 169-216: Add an integration regression test for
WorkerSelectionStage::select_pd_pair using four prefill and four decode workers,
with independent round-robin policies registered through PolicyRegistry. Invoke
select_pd_pair 40 times and assert each worker in both pools is selected exactly
10 times; ensure the stage obtains policies via get_prefill_policy and
get_decode_policy rather than calling RoundRobinPolicy directly, then run the
pr-test-analyzer agent to verify coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 774ff52c-bd54-4531-be87-1c99351ffa28

📥 Commits

Reviewing files that changed from the base of the PR and between 0c9e9fe and 4400175.

📒 Files selected for processing (2)
  • model_gateway/src/policies/round_robin.rs
  • model_gateway/src/routers/grpc/common/stages/worker_selection.rs

Comment on lines +169 to +216
#[test]
fn test_independent_policies_cover_all_workers_across_two_pools() {
fn make_workers(prefix: &str, n: usize) -> Vec<Arc<dyn Worker>> {
(0..n)
.map(|i| {
Arc::new(
BasicWorkerBuilder::new(format!("http://{prefix}{i}:8000"))
.worker_type(WorkerType::Regular)
.health_config(no_health_check())
.build(),
) as Arc<dyn Worker>
})
.collect()
}

let prefill_workers = make_workers("p", 4);
let decode_workers = make_workers("d", 4);
let info = SelectWorkerInfo::default();

let shared = RoundRobinPolicy::new();
let mut shared_prefill = [0usize; 4];
let mut shared_decode = [0usize; 4];
for _ in 0..40 {
let p = shared.select_worker(&prefill_workers, &info).unwrap();
let d = shared.select_worker(&decode_workers, &info).unwrap();
shared_prefill[p] += 1;
shared_decode[d] += 1;
}
assert_eq!(shared_prefill, [20, 0, 20, 0]);
assert_eq!(shared_decode, [0, 20, 0, 20]);

let prefill_policy = RoundRobinPolicy::new();
let decode_policy = RoundRobinPolicy::new();
let mut indep_prefill = [0usize; 4];
let mut indep_decode = [0usize; 4];
for _ in 0..40 {
let p = prefill_policy
.select_worker(&prefill_workers, &info)
.unwrap();
let d = decode_policy
.select_worker(&decode_workers, &info)
.unwrap();
indep_prefill[p] += 1;
indep_decode[d] += 1;
}
assert_eq!(indep_prefill, [10, 10, 10, 10]);
assert_eq!(indep_decode, [10, 10, 10, 10]);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🔴 Important Add a select_pd_pair integration regression test.

This test validates RoundRobinPolicy behavior only. It does not exercise the changed WorkerSelectionStage::select_pd_pair wiring.

Configure four prefill workers and four decode workers with round-robin policies. Call select_pd_pair 40 times. Assert that each prefill worker and each decode worker receives 10 selections. This test must use PolicyRegistry::get_prefill_policy and PolicyRegistry::get_decode_policy through the stage.

As per coding guidelines, “Run the pr-test-analyzer agent to verify that tests adequately cover new or changed functionality.”

🤖 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 `@model_gateway/src/policies/round_robin.rs` around lines 169 - 216, Add an
integration regression test for WorkerSelectionStage::select_pd_pair using four
prefill and four decode workers, with independent round-robin policies
registered through PolicyRegistry. Invoke select_pd_pair 40 times and assert
each worker in both pools is selected exactly 10 times; ensure the stage obtains
policies via get_prefill_policy and get_decode_policy rather than calling
RoundRobinPolicy directly, then run the pr-test-analyzer agent to verify
coverage.

Source: Coding guidelines

Add a WorkerSelectionStage regression that selects 4P+4D with
independent round_robin policies through get_prefill_policy /
get_decode_policy, locking the PD wiring (not just RoundRobinPolicy).

Signed-off-by: yangxurui <yangxurui@meituan.com>
Co-authored-by: longcat-ia-team <312376714+longcat-ia-team@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@OftenDream

Copy link
Copy Markdown
Contributor Author

Added an integration regression test in worker_selection.rs that exercises WorkerSelectionStage::select_pd_pair with 4 prefill + 4 decode workers and independent round-robin policies via PolicyRegistry::get_prefill_policy / get_decode_policy (40 selections → 10 each).

lightseek-bot and others added 5 commits August 3, 2026 09:48
The test module cannot see the parent's private use import, which
broke CI clippy/libtest compilation.

Signed-off-by: yangxurui <yangxurui@meituan.com>
Co-authored-by: longcat-ia-team <312376714+longcat-ia-team@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Align formatting with nightly rustfmt so CI fmt --check passes.

Signed-off-by: yangxurui <yangxurui@meituan.com>
Co-authored-by: longcat-ia-team <312376714+longcat-ia-team@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@slin1237
slin1237 merged commit def90a2 into smg-project:main Aug 4, 2026
27 of 39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

grpc gRPC client and router changes model-gateway Model gateway crate changes priority:high High priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants