feat(load-reporter): add push-based engine load reporting - #32523
Bakerjc-bgner wants to merge 52 commits into
Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
@hzh0425 and @whybeyoung Since the new code changes are quite extensive, I've split them into separate commits by module to make it easier to review. Could you please help arrange a code review? Thanks! 🙏 |
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
please resolve the conflicts. |
|
|
@Bakerjc-bgner some ci can't pass, seems this patch break something pls take a look https://github.com/sgl-project/sglang/actions/runs/32443308833/job/96658282007#step:15:109 |
Squashed port of upstream sgl-project/sglang#32523 (32 commits) onto the DeepSeek-v4 branch. Applied as the PR's net diff against its merge base (6127d1d) so none of upstream main's unrelated history comes along. Adds python/sglang/srt/load_reporter/: protocol/config, snapshot validation and building, rank-aware sampling, resilient report streams, lifecycle orchestration, and a bidi gRPC service the Router dials into. Wires it through the HTTP and gRPC entrypoints and the multi-tokenizer router. Two conflicts resolved against this branch's APIs rather than the PR's, because the PR's forms would fail at runtime here: - multi_tokenizer_mixin: zmq_reader_owner() takes (server_args, caller) on this branch; the PR's single-arg call would raise TypeError. Kept the two-arg call, took the PR's added load_reporter_port condition. - http_server: get_serving() is not imported in this file on this branch; get_serving().grpc_port would raise NameError. Used the existing server_args.grpc_port, kept the PR's single_tokenizer local. Verification is incomplete: this Windows host cannot import sglang at all ('resource' is POSIX-only), so only a py_compile syntax pass over all 16 touched Python files was possible (clean). The load_reporter unit and tokenizer tests still need to run on a Linux/DCU environment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
740e509 to
4a72a70
Compare
Squashed port of upstream sgl-project/sglang#32523 (32 commits) onto the DeepSeek-v4 branch. Applied as the PR's net diff against its merge base (6127d1d) so none of upstream main's unrelated history comes along. Adds python/sglang/srt/load_reporter/: protocol/config, snapshot validation and building, rank-aware sampling, resilient report streams, lifecycle orchestration, and a bidi gRPC service the Router dials into. Wires it through the HTTP and gRPC entrypoints and the multi-tokenizer router. Two conflicts resolved against this branch's APIs rather than the PR's, because the PR's forms would fail at runtime here: - multi_tokenizer_mixin: zmq_reader_owner() takes (server_args, caller) on this branch; the PR's single-arg call would raise TypeError. Kept the two-arg call, took the PR's added load_reporter_port condition. - http_server: get_serving() is not imported in this file on this branch; get_serving().grpc_port would raise NameError. Used the existing server_args.grpc_port, kept the PR's single_tokenizer local. Verification is incomplete: this Windows host cannot import sglang at all ('resource' is POSIX-only), so only a py_compile syntax pass over all 16 touched Python files was possible (clean). The load_reporter unit and tokenizer tests still need to run on a Linux/DCU environment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Preserve the source-backed SGLang error catalog and responsibility mapping. Describe AIgate error classification, published token limits, SSE error and usage handling, P/D cancellation, observability migration, and validation limits. Reference the corresponding AIgate implementation commit.
The implementation reference now lives in AIgate at /home/kaizhang36/go/src/dev/AIgate/docs/aigate-sglang-error-mapping.md. AIgate commit b814c951262608b57fd6d3f1cbe3d863016ea680 contains the migrated document, updated implementation details, and review regression coverage. Remove the former SGLang copy so the mapping is maintained with AIgate.
Merge sgl-project/sglang main at a1ec35a. Preserve upstream's ServerArgs split and resolution pipeline. Declare the optional reporter port in Observability and validate it before model loading. Read published parallel fields through the new direct namespace API in the HTTP, standalone gRPC, and multi-tokenizer reporter owners. Keep upstream Ruff formatting and evaluation dependencies. Align reporter CI registrations with the current test taxonomy, and cover HTTP/native gRPC ownership, startup failure cleanup, and multi-tokenizer lifecycle on CPU. Validation: CPU configuration/runtime, load reporting, snapshot, gRPC bridge, and lifecycle regressions; all applicable pre-commit checks on the exact merged tree relative to upstream/main. GPU end-to-end tests were not run on this CPU-only host.
Motivation
Load-aware routing needs one authoritative view of scheduler load across
data-parallel ranks. Polling every Worker from every Router adds fan-out,
creates inconsistent views, and churns connections.
This PR adds the Worker-side reporter: a push channel built on the scheduler's
existing snapshot publication. One shared pull per fire is broadcast to every
registered Router over long-lived bidirectional gRPC streams. Router-side
ingestion, discovery, retries, and the Prefill throughput extension are
intentionally split into follow-up PRs so each layer can be reviewed
independently.
Modifications
Architecture
flowchart LR Scheduler["Scheduler<br/>published per-DP-rank load snapshots"] Source["Per-mode snapshot source<br/>manager get_loads / Router SHM reader"] Fire["Single fire loop<br/>one pull per fire + rank-set validation"] Builder["LoadReport builder<br/>HEALTHY / STALE / UNREACHABLE"] Service["Worker gRPC service<br/>--load-reporter-port"] Router["Routers dial in<br/>drive Monitor streams"] Scheduler --> Source --> Fire --> Builder --> Service --> RouterProtocol and configuration
sglang.router.loadmonitor.v1.LoadMonitorService.Monitor(stream RouterFrame) returns (stream WorkerFrame)on a fixed, opt-in--load-reporter-port; eachexternal Router dials in and drives its own stream (
register→ ack →bounded first fire → periodic reports). Stable field numbers and enum values
are preserved.
RouterFrame=register | update_config | keep_alive | stop, withregisterrequired first;WorkerFrame=registered | report | error.Re-registering the same
router_idreplaces its old session; differentrouter_ids coexist.grpcioandprotobufthrough the optionalload-reporterextraacross all supported Python wheel variants.
runtime dependencies.
Reporter runtime — one timer, one pull, broadcast
(deadline, lease, capacity-1 queue) and own no task or timer.
get_loads(), 1 sbudget). The same budget covers one retry when the expected DP-rank set
changes mid-pull.
HEALTHY,STALE, orUNREACHABLE(empty ranks +last_error). There is no persistentstore and no cross-report merge, so a slow or stale rank is never replaced
with historical data.
sessions registered before the next fire share its pull for their initial
report.
renewal, mid-stream config updates, registration-anchored deadlines, and
idempotent shutdown.
request path.
Freshness
End-to-end snapshot freshness is bounded by the scheduler's snapshot
publication path (
load_snapshot_publish_interval), not by the gRPC deliverycadence. The report interval controls how often a report is sent, not how old
the snapshot inside it is — a poll at the same cadence observes data of the
same age.
What the push stream adds over polling is delivery, not freshness: a negotiated
per-Router cadence, connection reuse, one-pull multi-Router fan-out, leases,
and bounded backpressure.
Tokenizer integration
FastAPI lifespan (native gRPC reuses the same process and listener).
MultiTokenizerRouteris the sole runtime owner; HTTPworkers open no streams, and elastic scale changes update the expected
DP-rank set (observed by the next fire).
servicers without the readiness hook fail loudly when the reporter is
enabled.
the HTTP-server lifespan, the SMG gRPC-server finally path, and
MultiTokenizerRouter.close().Tests and documentation
grpc.aio): proto contract,fire loop (shared pull deadlines, broadcast to due sessions, per-session
lease gating, rank-set-change retry sharing one budget, registration-anchored
cadence, stale/error reports, re-registration, shutdown), snapshot validation
and report-builder contracts, snapshot sources, service handshake and error
frames, composition-root lifecycle, and standalone SMG wiring.
topology updates never pull immediately.
grpc.aiofake Router coversingle-owner, multi-owner, and standalone SMG reporting.
schedule, freshness model, network/deployment assumptions, and shutdown
behavior.
Design advantages
into the reporting graph; there is no per-request overhead.
persistent bidi streams, no Router-side polling fan-out or connection churn.
validated and retried within the same fire budget.
latest-wins backpressure, and bounded shutdown prevent stale tasks from
accumulating.
a clean foundation for the separately reviewed Router monitor and future
metrics.
Accuracy Tests
N/A for model accuracy. This PR does not change model forward code, kernels,
sampling, or generated outputs.
Functional validation:
scheduling/broadcast, snapshot validation, report builder, service behavior,
lifecycle, and standalone SMG wiring.
grpc.aiofake Router againstsingle-owner, multi-owner, and standalone SMG modes.
sglang.router.loadmonitor.v1service.Speed Tests and Profiling
N/A for inference throughput benchmarking. This is an opt-in control-plane
feature and does not modify model execution.
The reporter adds no request-path overhead: there are no hooks on the
dispatch/completion paths, and sampling/network I/O runs in the single
background fire task. No inference-speed improvement is claimed. Reporter
cadence and freshness are exercised functionally by the registered tests; no
new micro-benchmarks are claimed in this revision.
Checklist
Review and Merge Process
/tag-and-rerun-ci,/tag-run-ci-label,/rerun-failed-ci.CI States
Latest PR Test (Base): ❌ Run #34449344106
Latest PR Test (Extra): ❌ Run #34449343918
Latest PR Test (AMD ROCm 10): ❌ Run #34449344253