Skip to content

feat(grpc-servicer): add Prometheus /metrics sidecar#1782

Open
slin1237 wants to merge 1 commit into
mainfrom
feat/metrics-w4-servicer-sidecar
Open

feat(grpc-servicer): add Prometheus /metrics sidecar#1782
slin1237 wants to merge 1 commit into
mainfrom
feat/metrics-w4-servicer-sidecar

Conversation

@slin1237

@slin1237 slin1237 commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Part of #1773. Closes #1777.

What

SMG's gRPC servicers exposed no HTTP /metrics. This adds a shared, dependency-light, best-effort sidecar so they're scrape-able in gRPC mode (the producer side of "enable that for other engines"):

  • smg_grpc_servicer/metrics.py: stdlib-asyncio + prometheus_client /metrics server; bind/serve failures are logged and swallowed so the gRPC server keeps serving. SchedulerLoadCollector re-exposes the GetLoads snapshot for engines without a native registry.
  • Started alongside serve_grpc for sglang and tokenspeed (mlx excluded — no PD). Port via --metrics-port / SMG_METRICS_PORT.
  • Advertises metrics_port (always, when enabled) + metrics_url (only when the host is routable; omitted for 0.0.0.0) in GetServerInfo.server_args, so the gateway (W1, [Metrics] W1: gRPC engine-metrics scraping (/engine_metrics across transports) #1774) auto-discovers it.

Tests

20 engine-free sidecar/collector tests (incl. a real HTTP round-trip asserting valid exposition + content-type, and a best-effort bind-failure path) + 3 import-gated servicer tests (verified via a minimal tokenspeed stub). python -m pytest grpc_servicer/tests → 91 passed / 5 skipped; ruff check/format --check clean. No Rust changes (cargo not run).

Cross-workstream notes (action on the W1 side, #1774)

  • This PR advertises metrics_port and metrics_url. W1's SGLANG_GRPC_KEYS allowlists metrics_url (✓ end-to-end for routable hosts) but not metrics_port, and doesn't extend TOKENSPEED_GRPC_KEYS. Follow-ups on the W1 side: allowlist metrics_port and add the keys to TOKENSPEED_GRPC_KEYS.
  • vLLM intentionally out of scope: there's no vllm/server.py here (vLLM is bootstrapped by upstream vllm serve --grpc, which serves its own /metrics), and vllm_engine GetServerInfo has no server_args Struct (advertising would need a proto field — a Rust workstream).
  • tokenspeed/sglang token_usage in the sidecar is 0.0 (needs an async scheduler round-trip unsafe from a sync Prometheus collect()); full usage remains available via the GetLoads RPC.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added an optional Prometheus /metrics HTTP sidecar for gRPC servicers, configurable via --metrics-port / metrics_port (disabled when None).
    • GetServerInfo now advertises metrics_port and a reachable metrics_url when metrics are enabled; wildcard-like hosts suppress the URL.
  • Dependency Updates

    • Added prometheus-client as a required runtime dependency.
  • Tests

    • Expanded sidecar coverage, including slow-header robustness (header drip/timeout handling).
    • Added tests validating metrics advertisement and load snapshot behavior for both scheduler types.

@slin1237 slin1237 requested a review from CatherineSue as a code owner June 18, 2026 05:43
@slin1237 slin1237 added enhancement New feature or request grpc gRPC client and router changes metrics-consolidation Epic: Engine Metrics Consolidation & PD Observability labels Jun 18, 2026
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a best-effort Prometheus /metrics sidecar for gRPC servicers, with shared metrics helpers, SGLang and TokenSpeed wiring, GetServerInfo.server_args advertising, a TokenSpeed CLI flag, and tests for HTTP and RPC behavior.

Changes

Prometheus /metrics sidecar for gRPC servicers

Layer / File(s) Summary
Core sidecar module
grpc_servicer/pyproject.toml, grpc_servicer/smg_grpc_servicer/metrics.py
Adds prometheus-client>=0.20.0 and a shared metrics module with port resolution, routable URL generation, server-args construction, SchedulerLoadCollector, MetricsSidecar, request handling, and best-effort startup.
SGLang servicer and server wiring
grpc_servicer/smg_grpc_servicer/sglang/servicer.py, grpc_servicer/smg_grpc_servicer/sglang/server.py
Adds metrics-port storage, metrics-sidecar discovery args, load snapshots, sidecar startup, bound-port propagation, and shutdown cleanup for SGLang.
TokenSpeed servicer, server, and CLI wiring
grpc_servicer/smg_grpc_servicer/tokenspeed/servicer.py, grpc_servicer/smg_grpc_servicer/tokenspeed/server.py, grpc_servicer/smg_grpc_servicer/tokenspeed/__main__.py
Adds metrics-port storage, discovery args, load snapshots, sidecar startup and shutdown, and --metrics-port CLI parsing for TokenSpeed.
Metrics helpers and RPC advertisement tests
grpc_servicer/tests/test_metrics_sidecar.py, grpc_servicer/tests/test_servicer_metrics_advertise.py
Covers helper validation, collector emission, sidecar HTTP routing and timeout handling, and GetServerInfo metrics advertisement for TokenSpeed and SGLang.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as TokenSpeed CLI
  participant Serve as serve_grpc
  participant Sidecar as MetricsSidecar
  participant Servicer as SchedulerServicer
  participant Scraper as Prometheus scraper

  CLI->>Serve: metrics_port
  Serve->>Sidecar: start()
  Sidecar-->>Serve: bound port
  Serve->>Servicer: store metrics_port
  Scraper->>Sidecar: GET /metrics
  Sidecar-->>Scraper: Prometheus exposition
  Servicer-->>CLI: GetServerInfo.server_args
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

  • lightseekorg/smg#638: Related through the added prometheus-client runtime dependency in pyproject.toml.
  • lightseekorg/smg#1464: Related through the TokenSpeed servicer startup and GetServerInfo metadata paths extended here.

Suggested labels

dependencies

Suggested reviewers

  • CatherineSue

Poem

🐇 I hop to the port with a Prometheus grin,
GET /metrics now lets the gauges stream in.
Two servicers whisper their ports to the light,
And the rabbit keeps watch through the midnight.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR covers sglang and tokenspeed, but #1777 also calls for the shared sidecar on vllm and the PR does not touch it. Add the metrics sidecar and server_args advertisement for vllm too, or update the linked issue scope if vllm is intentionally excluded.
Docstring Coverage ⚠️ Warning Docstring coverage is 23.68% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding a Prometheus /metrics sidecar to grpc servicers.
Out of Scope Changes check ✅ Passed The changes stay focused on metrics plumbing and tests; no clearly unrelated code appears in the diff.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/metrics-w4-servicer-sidecar

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

@github-actions github-actions Bot added dependencies Dependency updates tests Test changes labels Jun 18, 2026

@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 introduces a lightweight, best-effort Prometheus /metrics HTTP sidecar for the gRPC servicers (sglang and tokenspeed), allowing per-worker metrics to be scraped over plain HTTP. It adds a custom MetricsSidecar server using asyncio and a SchedulerLoadCollector to expose scheduler load snapshots. The feedback highlights critical improvements for the custom HTTP server implementation: adding read timeouts and EOF checks to prevent Slowloris-style resource exhaustion, awaiting writer.wait_closed() to avoid socket resource leaks, and wrapping the snapshot retrieval in a try-except block to ensure a single failure does not crash the entire metrics scrape.

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 grpc_servicer/smg_grpc_servicer/metrics.py Outdated
Comment thread grpc_servicer/smg_grpc_servicer/metrics.py
Comment thread grpc_servicer/smg_grpc_servicer/metrics.py Outdated
@claude

claude Bot commented Jun 18, 2026

Copy link
Copy Markdown

👋 The PR description doesn't fully follow
PULL_REQUEST_TEMPLATE.md:

  • Missing header: ## Description
  • Missing header: ### Problem
  • Missing header: ### Solution
  • Missing header: ## Changes
  • Missing header: ## Test Plan

Please update the PR description so reviewers have the context they need.

Comment thread grpc_servicer/smg_grpc_servicer/tokenspeed/servicer.py Outdated

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

Clean, well-structured PR. One nit on the tokenspeed load_snapshot waiting-count logic (see inline comment). No blocking issues.

Summary: 0 🔴 Important · 1 🟡 Nit · 0 🟣 Pre-existing

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3e9c6d3634

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread grpc_servicer/smg_grpc_servicer/tokenspeed/server.py Outdated
Comment thread grpc_servicer/smg_grpc_servicer/sglang/server.py Outdated

@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: 4

🤖 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 `@grpc_servicer/smg_grpc_servicer/metrics.py`:
- Around line 45-58: The explicit metrics_port parameter is returned without
validation when it's not None, bypassing the range checks that are applied to
the environment variable input. Add the same port range validation (0 < port <
65536) to the explicit parameter before returning it, ensuring that invalid port
values cannot be advertised or passed into startup paths regardless of whether
they come from the explicit parameter or the METRICS_PORT_ENV environment
variable.
- Around line 69-71: The metrics_url function constructs URLs without accounting
for IPv6 addresses, which require bracket notation in URLs. Before building the
URL string with the host and port, add a check to determine if the host is an
IPv6 address. If it is an IPv6 literal, wrap it in brackets when constructing
the f-string. This ensures the resulting URL is valid and unambiguous for both
IPv4 and IPv6 hosts.

In `@grpc_servicer/smg_grpc_servicer/sglang/server.py`:
- Around line 313-318: The metrics_port is being advertised before confirming
the actual port that the metrics sidecar successfully bound to. After awaiting
the start_metrics_sidecar call in the block where enableLanceKnowledgeBase-like
conditions are checked, extract the actual bound port from the returned
metrics_sidecar object and reconcile it with the advertised metrics_port. Ensure
that GetServerInfo publishes only the port that the sidecar actually bound to,
not the requested port, to prevent advertising unreachable endpoints when the
bind fails or a different port is used.

In `@grpc_servicer/smg_grpc_servicer/tokenspeed/server.py`:
- Around line 134-139: The metrics sidecar is started via the
start_metrics_sidecar function but the servicer.metrics_port is never updated
with the actual port that the sidecar is running on, which can cause service
discovery to advertise an incorrect or dead metrics endpoint. After the await
start_metrics_sidecar call completes and assigns the result to metrics_sidecar,
extract the actual metrics port from the metrics_sidecar object and assign it to
servicer.metrics_port to ensure the advertised metadata reflects the real
sidecar state.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 76079758-704f-44fc-ba1a-aeb2a2e2bc10

📥 Commits

Reviewing files that changed from the base of the PR and between 1288d16 and 3e9c6d3.

📒 Files selected for processing (9)
  • grpc_servicer/pyproject.toml
  • grpc_servicer/smg_grpc_servicer/metrics.py
  • grpc_servicer/smg_grpc_servicer/sglang/server.py
  • grpc_servicer/smg_grpc_servicer/sglang/servicer.py
  • grpc_servicer/smg_grpc_servicer/tokenspeed/__main__.py
  • grpc_servicer/smg_grpc_servicer/tokenspeed/server.py
  • grpc_servicer/smg_grpc_servicer/tokenspeed/servicer.py
  • grpc_servicer/tests/test_metrics_sidecar.py
  • grpc_servicer/tests/test_servicer_metrics_advertise.py

Comment thread grpc_servicer/smg_grpc_servicer/metrics.py Outdated
Comment thread grpc_servicer/smg_grpc_servicer/metrics.py Outdated
Comment thread grpc_servicer/smg_grpc_servicer/sglang/server.py
Comment thread grpc_servicer/smg_grpc_servicer/tokenspeed/server.py
@mergify

mergify Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Hi @slin1237, this PR has merge conflicts that must be resolved before it can be merged. Please rebase your branch:

git fetch origin main
git rebase origin/main
# resolve any conflicts, then:
git push --force-with-lease

@mergify mergify Bot added the needs-rebase PR has merge conflicts that need to be resolved label Jun 18, 2026
slin1237 added a commit that referenced this pull request Jun 18, 2026
Signed-off-by: Simo Lin <25425177+slin1237@users.noreply.github.com>
@slin1237 slin1237 force-pushed the feat/metrics-w4-servicer-sidecar branch from 3e9c6d3 to 5ddf6fc Compare June 18, 2026 17:01
@slin1237

Copy link
Copy Markdown
Collaborator Author

Addressed review feedback (new commit on top of a rebase onto main):

Rebase: Rebased onto origin/main; resolved the grpc_servicer/pyproject.toml conflict by keeping both — main's raised grpc dependency floors (grpcio*>=1.81.1, #1785) and this PR's prometheus-client>=0.20.0.

Fixes:

  • SECURITY-HIGH metrics.py _handle: wrapped both reader.readline() calls in asyncio.wait_for(..., timeout=5.0) and added EOF/immediate-disconnect early-return — prevents a Slowloris-style hang. (_READ_TIMEOUT = 5.0)
  • MEDIUM _handle finally: await writer.wait_closed() after writer.close() (try/except guarded) to fully release the socket.
  • MEDIUM SchedulerLoadCollector.collect: wrapped _snapshot_fn() in try/except — a failing snapshot logs a warning and exposes an empty snapshot instead of breaking the whole /metrics scrape.
  • nit tokenspeed/servicer.py load_snapshot: num_waiting_reqs=0.0 and num_total_reqs=running only (can't distinguish waiting from running without a scheduler round-trip; mirrors sglang's load_snapshot).
  • P2 sglang/server.py + tokenspeed/server.py: construct the servicer with metrics_port=None; set servicer.metrics_port = sidecar.port (the real bound port) only after start_metrics_sidecar returns successfully. A failed bind (None) leaves it None, so GetServerInfo never advertises a requested-but-unbound port or 0.
  • MAJOR resolve_metrics_port: the explicit argument now goes through the same 0 < port < 65536 int-coercion/validation as the env var (shared _coerce_port); invalid → None + warning.
  • nit metrics_url: bare IPv6 literals are now bracketed (http://[::1]:9100/metrics).

Tests (pytest grpc_servicer/tests): 101 passed, 6 skipped (skips are engine/zmq import-gated: vllm/zmq/tokenspeed/sglang not installed locally — they run in CI). Added/extended coverage: explicit-port validation, IPv6 URL bracketing, advertise-bound-port-not-zero, failed-bind-advertises-nothing, collector tolerates a raising snapshot, _handle EOF + read-timeout, tokenspeed load_snapshot running-only. ruff format + ruff check grpc_servicer clean.

@mergify mergify Bot removed the needs-rebase PR has merge conflicts that need to be resolved label Jun 18, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ddf6fc7ef

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread grpc_servicer/smg_grpc_servicer/metrics.py

@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 `@grpc_servicer/smg_grpc_servicer/metrics.py`:
- Around line 170-179: The timeout is applied individually to each readline()
call within the while loop that reads headers, allowing a slow client to send
one header line just under the _READ_TIMEOUT limit repeatedly and keep the
handler open indefinitely. To fix this, introduce a cumulative timeout for the
entire header-read phase: record the start time before the while loop, and for
each asyncio.wait_for() call within that loop (starting with the one in the
while True block), calculate the remaining time budget by subtracting the
elapsed time from _READ_TIMEOUT and use this remaining time as the timeout
value. This ensures the timeout exception fires if the client doesn't complete
all headers within the total timeout window.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 12bee1f6-0fcb-4412-aaf8-0dfd7370bb83

📥 Commits

Reviewing files that changed from the base of the PR and between 3e9c6d3 and 5ddf6fc.

📒 Files selected for processing (9)
  • grpc_servicer/pyproject.toml
  • grpc_servicer/smg_grpc_servicer/metrics.py
  • grpc_servicer/smg_grpc_servicer/sglang/server.py
  • grpc_servicer/smg_grpc_servicer/sglang/servicer.py
  • grpc_servicer/smg_grpc_servicer/tokenspeed/__main__.py
  • grpc_servicer/smg_grpc_servicer/tokenspeed/server.py
  • grpc_servicer/smg_grpc_servicer/tokenspeed/servicer.py
  • grpc_servicer/tests/test_metrics_sidecar.py
  • grpc_servicer/tests/test_servicer_metrics_advertise.py

Comment thread grpc_servicer/smg_grpc_servicer/metrics.py Outdated
slin1237 added a commit that referenced this pull request Jun 18, 2026
Signed-off-by: Simo Lin <25425177+slin1237@users.noreply.github.com>
@slin1237

Copy link
Copy Markdown
Collaborator Author

Round-2 review fixes pushed (36ed6e0):

  • Bounded the whole header-read phase (request line + headers) under a single _READ_TIMEOUT deadline instead of one timeout per readline(). Previously a Slowloris client dripping one header line every < 5s reset the clock each line and held a handler open indefinitely. Extracted MetricsSidecar._read_head and wrapped the single call in asyncio.wait_for(...); EOF early-return and best-effort behavior preserved.
  • Added test_handle_times_out_slow_header_drip (header-drip Slowloris) alongside the existing slow-request test.

Resolved 8 addressed review threads (whole-phase timeout, read-timeout/EOF, writer.wait_closed, collect() try-except, tokenspeed waiting count, advertise-only-bound-port x2, gateway-allowlist). The gateway-allowlist thread was replied to: it is handled in the W1 PR (#1779) — metrics_url is allowlisted there; the metrics_port alias + TokenSpeed key coverage is a tracked W1 follow-up.

Verification: ruff format --check + ruff check grpc_servicer clean; sidecar suite 31 passed, 4 skipped (engine-gated). (The 5 test_dp_proto_fields.py failures are pre-existing in this env — the published smg-grpc-proto==0.4.10 predates the data_parallel_* fields — and are unrelated to this change.)

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 36ed6e0a37

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread grpc_servicer/smg_grpc_servicer/metrics.py Outdated
The Rust gateway scrapes per-worker engine metrics over HTTP, but the gRPC
servicers (sglang, tokenspeed) had no HTTP endpoint to scrape. Add a shared,
dependency-light (stdlib asyncio + prometheus_client) best-effort /metrics
sidecar started alongside serve_grpc; any bind/serve failure is logged and
swallowed so the gRPC server keeps serving.

- metrics.py: the asyncio sidecar (one whole-head-phase read deadline so a
  Slowloris client can't pin a handler open), a SchedulerLoadCollector that
  re-exposes the GetLoads scheduler snapshot for engines without a native
  registry (tokenspeed), and metrics_url/metrics_server_args helpers.
- Advertise the sidecar to the gateway via GetServerInfo.server_args:
  metrics_port always, plus metrics_url only for a routable bind host.
  Wildcard and loopback binds aren't reachable across the network, so only the
  port is advertised and the gateway pairs it with the discovered worker
  address.
- Advertise only the actually-bound port, set after a successful start; a
  failed bind advertises nothing.
- sglang/tokenspeed: --metrics-port (or SMG_METRICS_PORT) wiring.

Part of #1773. Closes #1777.

Signed-off-by: Simo Lin <linsimo.mark@gmail.com>
@slin1237 slin1237 force-pushed the feat/metrics-w4-servicer-sidecar branch from 36ed6e0 to c26f066 Compare June 29, 2026 13:22

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c26f0660e4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

}
)
# Wildcard host: only the port is advertised (gateway knows the real address).
servicer.server_args = SimpleNamespace(host="0.0.0.0")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use a dataclass ServerArgs stub for SGLang test

When sglang is installed, this test invokes SGLangSchedulerServicer.GetServerInfo, whose first statement serializes self.server_args with dataclasses.asdict(...); the SimpleNamespace assigned here is not a dataclass, so the test raises TypeError: asdict() should be called on dataclass instances before it ever checks the metrics keys. Use a real ServerArgs instance/dataclass stub here, or add a production fallback before enabling this coverage.

Useful? React with 👍 / 👎.

@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 `@grpc_servicer/smg_grpc_servicer/sglang/servicer.py`:
- Line 579: Update GetServerInfo in servicer.py so it can serialize server_args
when it is not a dataclass. The current dataclasses.asdict(self.server_args)
path should be guarded with a fallback to a __dict__-based conversion, matching
the behavior already used by TokenSpeed, and then continue merging in
_metrics_server_args() so the metrics advertisement path works with
SimpleNamespace and other non-dataclass wrappers.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 35ac3e42-b0a1-432d-8b0a-1d85a45bf4eb

📥 Commits

Reviewing files that changed from the base of the PR and between 36ed6e0 and c26f066.

📒 Files selected for processing (9)
  • grpc_servicer/pyproject.toml
  • grpc_servicer/smg_grpc_servicer/metrics.py
  • grpc_servicer/smg_grpc_servicer/sglang/server.py
  • grpc_servicer/smg_grpc_servicer/sglang/servicer.py
  • grpc_servicer/smg_grpc_servicer/tokenspeed/__main__.py
  • grpc_servicer/smg_grpc_servicer/tokenspeed/server.py
  • grpc_servicer/smg_grpc_servicer/tokenspeed/servicer.py
  • grpc_servicer/tests/test_metrics_sidecar.py
  • grpc_servicer/tests/test_servicer_metrics_advertise.py

return str(obj)

serializable_args = make_serializable(server_args_dict)
serializable_args.update(self._metrics_server_args())

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 | ⚡ Quick win

Handle non-dataclass server_args in GetServerInfo.

Line 579 extends this RPC for metrics discovery, but dataclasses.asdict(self.server_args) above still raises on the SimpleNamespace stub used by grpc_servicer/tests/test_servicer_metrics_advertise.py. TokenSpeed already falls back to __dict__; mirroring that here keeps the new advertisement path callable in tests and any non-dataclass wrappers.

Proposed fix
-        server_args_dict = dataclasses.asdict(self.server_args)
+        if dataclasses.is_dataclass(self.server_args) and not isinstance(self.server_args, type):
+            server_args_dict = dataclasses.asdict(self.server_args)
+        else:
+            server_args_dict = dict(getattr(self.server_args, "__dict__", {}))
         server_args_struct = Struct()
🤖 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 `@grpc_servicer/smg_grpc_servicer/sglang/servicer.py` at line 579, Update
GetServerInfo in servicer.py so it can serialize server_args when it is not a
dataclass. The current dataclasses.asdict(self.server_args) path should be
guarded with a fallback to a __dict__-based conversion, matching the behavior
already used by TokenSpeed, and then continue merging in _metrics_server_args()
so the metrics advertisement path works with SimpleNamespace and other
non-dataclass wrappers.

@mergify

mergify Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Hi @slin1237, this PR has merge conflicts that must be resolved before it can be merged. Please rebase your branch:

git fetch origin main
git rebase origin/main
# resolve any conflicts, then:
git push --force-with-lease

@mergify mergify Bot added the needs-rebase PR has merge conflicts that need to be resolved label Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Dependency updates enhancement New feature or request grpc gRPC client and router changes metrics-consolidation Epic: Engine Metrics Consolidation & PD Observability needs-rebase PR has merge conflicts that need to be resolved tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Metrics] W4: Python servicer HTTP /metrics sidecar

1 participant