Skip to content

rollout: consistent_hashing/manual routing for inference_rollout stack - #1703

Merged
Zhichenzzz merged 4 commits into
mainfrom
yueming/new-stack-consistent-hashing
Jul 20, 2026
Merged

rollout: consistent_hashing/manual routing for inference_rollout stack#1703
Zhichenzzz merged 4 commits into
mainfrom
yueming/new-stack-consistent-hashing

Conversation

@yueming-yuan

@yueming-yuan yueming-yuan commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Problem

The consistent_hashing router policy needs every generation request to carry an X-SMG-Routing-Key header; a request without the key silently degrades — the router's implicit-key fallback can hash a constant authorization header and pin all traffic to a single engine (the failure mode of #1657). The client half of this contract was only implemented in the legacy stack (#891): sglang_rollout.generate_and_rm_group assigns per-sample keys and generate() attaches the header. The inference_rollout stack has neither — which is why --sglang-router-policy was hard-blocked under MILES_EXPERIMENTAL_ROLLOUT_REFACTOR=1. The eval paths of both stacks also never assign keys, and #1690 is about to make manual a second routing-key-based policy with its own scattered == "consistent_hashing" checks.

Fix

  • Rename Sample.session_idSample.routing_key (review feedback): the field is the per-sample routing key sent as X-SMG-Routing-Key, not a session — the new name disambiguates it from the session server's and the p2p transfer engine's session ids. Renamed repo-wide.
  • One predicate for all sites: policy_uses_routing_key(args) (consistent_hashing or manual) in generate_endpoint_utils, used by every key site — both stacks' group assignment and eval, compute_routing_headers, prefill-recompute batch gating and per-sample headers. The legacy generate() and prefill per-sample path now reuse compute_routing_headers instead of hand-building the header. This closes the coordination gap with [router] set manual policy (sticky + min_load) as default agentic routing policy #1690: manual gets keys on all paths, not just the two legacy-stack sites, and a future key-based policy is a one-line change.
  • inference_rollout_common.generate_and_rm_group assigns a per-sample routing_key (mirrors the legacy stack); generate_hub.single_turn / generate_hub.multi_turn attach the header.
  • Both stacks' eval_rollout_single_dataset mint an independent uuid per eval sample, so eval traffic spreads across engines while each sample stays pinned.
  • Drop the MILES_EXPERIMENTAL_ROLLOUT_REFACTOR=1 restriction on --sglang-router-policy.

Enforcement lives router-side: radixark/sgl-router-for-miles#8 rejects keyless requests with 400 missing_routing_key under consistent_hashing/manual policies (escape hatch: --allow-requests-without-routing-key). The router is the only chokepoint that sees every client — including proxy layers and raw-aiohttp callers that bypass miles' http utils — so this PR carries no client-side check.

Compat notes for the rename: pickled Samples in old partial-rollout buffers / debug dumps restore the stale session_id attr; the new field defaults to None and gets a fresh routing key on the next submit — affinity resets once across restart, harmless. Out-of-repo code reading sample.session_id must switch to sample.routing_key.

Validation

  • Smoke tests: policy_uses_routing_key truth table (consistent_hashing/manual → true; None/cache_aware → false); compute_routing_headers attaches the header iff predicate + key set; batch prefill scoring disabled for both key policies; reset_for_retry preserves routing_key.
  • pre-commit run --all-files passes. Generate paths are unchanged when the policy is off (headers=None as before).

🤖 Generated with Claude Code

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request implements sticky routing for the consistent_hashing router policy by generating a unique session_id for each sample and passing it as an X-SMG-Routing-Key header in generation requests. It also adds a check in the HTTP utility to ensure this header is present for relevant endpoints when consistent hashing is enabled. The review feedback suggests replacing an assert statement with a ValueError in the routing key validation check to prevent it from being bypassed when Python is run with optimizations.

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 thread miles/utils/http_utils.py Outdated
Comment on lines +321 to +325
assert headers is not None and any(k.lower() == _ROUTING_KEY_HEADER.lower() for k in headers), (
f"consistent_hashing router policy requires an {_ROUTING_KEY_HEADER} header on {parts.path} requests, "
f"but none was attached (url={url}). Set sample.session_id before generating so the generate "
f"function can attach the routing key."
)

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.

medium

According to the project guidelines, ValueError should be used instead of assert for validating function arguments. Using assert can be bypassed if Python is run with optimizations (-O), which would silently disable this critical routing check.

Suggested change
assert headers is not None and any(k.lower() == _ROUTING_KEY_HEADER.lower() for k in headers), (
f"consistent_hashing router policy requires an {_ROUTING_KEY_HEADER} header on {parts.path} requests, "
f"but none was attached (url={url}). Set sample.session_id before generating so the generate "
f"function can attach the routing key."
)
if headers is None or not any(k.lower() == _ROUTING_KEY_HEADER.lower() for k in headers):
raise ValueError(
f"consistent_hashing router policy requires an {_ROUTING_KEY_HEADER} header on {parts.path} requests, "
f"but none was attached (url={url}). Set sample.session_id before generating so the generate "
f"function can attach the routing key."
)
References
  1. Use ValueError instead of assert for validating function or constructor arguments (such as checking for positive or non-negative values).

@yueming-yuan
yueming-yuan force-pushed the yueming/new-stack-consistent-hashing branch 2 times, most recently from 1bf4d11 to 48c6509 Compare July 17, 2026 21:03

def compute_routing_headers(args, sample: Sample) -> dict[str, str] | None:
if args.sglang_router_policy == "consistent_hashing" and sample.session_id:
return {"X-SMG-Routing-Key": sample.session_id}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

To avoid confusion with session server's session id, could you also modify the sample.session_id to sample.sglang_router_session_id?

@yueming-yuan
yueming-yuan force-pushed the yueming/new-stack-consistent-hashing branch 2 times, most recently from 9122755 to d79eddf Compare July 17, 2026 21:13
@guapisolo

Copy link
Copy Markdown
Collaborator

Good fix.
I think the session server should also generate a unique hash key, and append it into all request header. Then the harness has no need to care about the headers? What's your point.

@yueming-yuan
yueming-yuan force-pushed the yueming/new-stack-consistent-hashing branch from d79eddf to 7daffd4 Compare July 17, 2026 21:23
@yueming-yuan

Copy link
Copy Markdown
Collaborator Author

@guapisolo yes if the user is using the session server then it's perfect. But in case some users might vibe their own session server, and they might not know adding this key..

@guapisolo guapisolo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@yueming-yuan

Copy link
Copy Markdown
Collaborator Author

Update: dropped the client-side check from this PR — keyless-request enforcement moved to the router, where it covers every client (session server, custom proxy layers, raw aiohttp callers) instead of only requests going through miles' http_utils: radixark/sgl-router-for-miles#8. Both consistent_hashing and manual policies now reject keyless requests with 400 missing_routing_key by default; --allow-requests-without-routing-key disables the check.

…ollout stack

- rename Sample.session_id to Sample.routing_key to disambiguate from the
  session server's and p2p transfer engine's session ids
- unify all routing-key sites behind policy_uses_routing_key, covering the
  manual policy (#1690) as well: both stacks' group assignment and eval,
  single_turn/multi_turn/legacy generate headers, prefill recompute
- drop the MILES_EXPERIMENTAL_ROLLOUT_REFACTOR=1 restriction on
  --sglang-router-policy

Keyless-request enforcement lives router-side
(radixark/sgl-router-for-miles#8), which covers every client including
proxy layers that bypass miles' http utils.
@yueming-yuan
yueming-yuan force-pushed the yueming/new-stack-consistent-hashing branch from 289ca4b to dd2a6cc Compare July 17, 2026 22:44
@yueming-yuan yueming-yuan changed the title rollout: support consistent_hashing routing in the inference_rollout stack rollout: support consistent_hashing routing and manual policy with min_load in the inference_rollout stack Jul 17, 2026
yueming-yuan and others added 3 commits July 20, 2026 11:51
assert is stripped entirely under python -O / PYTHONOPTIMIZE=1, which
would silently skip this check and reintroduce the keyless-request
degradation this PR fixes. Enforcement now lives router-side too
(sgl-router-for-miles#8), so this is defense-in-depth, but it should
still fail loudly rather than be optimizable away.

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

LGTM!

@Zhichenzzz Zhichenzzz changed the title rollout: support consistent_hashing routing and manual policy with min_load in the inference_rollout stack rollout: consistent_hashing/manual routing for inference_rollout stack Jul 20, 2026
@Zhichenzzz
Zhichenzzz merged commit b93219b into main Jul 20, 2026
36 checks passed
@Zhichenzzz
Zhichenzzz deleted the yueming/new-stack-consistent-hashing branch July 20, 2026 21:27
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.

3 participants