Skip to content

[Serve] Instrument ray_serve_replica_state metric - #62860

Open
petern48 wants to merge 12 commits into
ray-project:masterfrom
petern48:replica_state_metric
Open

[Serve] Instrument ray_serve_replica_state metric#62860
petern48 wants to merge 12 commits into
ray-project:masterfrom
petern48:replica_state_metric

Conversation

@petern48

@petern48 petern48 commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Description

Instrument ray_serve_replica_state, which will enable us to observe "Replica Status Over Time."

Related issues

Fixes #59699

Additional information

It emits the existing ReplicaStates with the following int values as a gauge.

class ReplicaState(str, Enum):
STARTING = "STARTING"
UPDATING = "UPDATING"
RECOVERING = "RECOVERING"
RUNNING = "RUNNING"
STOPPING = "STOPPING"
PENDING_MIGRATION = "PENDING_MIGRATION"

        1=STARTING, 2=UPDATING, 3=RECOVERING, 4=RUNNING,
        5=STOPPING, 6=PENDING_MIGRATION.

Signed-off-by: Peter Nguyen <petern0408@gmail.com>
Signed-off-by: Peter Nguyen <petern0408@gmail.com>

@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 new metric, "serve_replica_state", to track the lifecycle states of Ray Serve deployment replicas. It adds a numeric mapping for states and updates the controller to report these values via a gauge. Feedback focuses on a performance regression where the "is_new_replica" check in "ReplicaStateContainer.add" triggers redundant callbacks on every controller tick due to the internal "pop"-and-"add" pattern. This leads to excessive metric updates and prevents the controller from reaching a steady state. It is recommended to implement a state cache to guard against these redundant calls and ensure the "_in_transition" flag is only set during actual state transitions.

Comment thread python/ray/serve/_private/deployment_state.py Outdated
Comment thread python/ray/serve/_private/deployment_state.py
Comment thread python/ray/serve/_private/deployment_state.py Outdated
Signed-off-by: Peter Nguyen <petern0408@gmail.com>
Signed-off-by: Peter Nguyen <petern0408@gmail.com>
Signed-off-by: Peter Nguyen <petern0408@gmail.com>
@petern48
petern48 marked this pull request as ready for review April 22, 2026 19:17
@petern48
petern48 requested a review from a team as a code owner April 22, 2026 19:17
Comment thread python/ray/serve/_private/common.py Outdated
Comment thread python/ray/serve/_private/deployment_state.py Outdated
@ray-gardener ray-gardener Bot added serve Ray Serve Related Issue observability Issues related to the Ray Dashboard, Logging, Metrics, Tracing, and/or Profiling community-contribution Contributed by the community labels Apr 22, 2026
Signed-off-by: Peter Nguyen <petern0408@gmail.com>
Comment thread python/ray/serve/_private/deployment_state.py Outdated
Signed-off-by: Peter Nguyen <petern0408@gmail.com>
Signed-off-by: Peter Nguyen <petern0408@gmail.com>
@petern48 petern48 changed the title [Serve] Instrument ray_serve_replica_state [Serve] Instrument ray_serve_replica_state metric Apr 23, 2026
@petern48
petern48 requested a review from abrarsheikh April 23, 2026 15:04

# Refresh replica_state_gauge for every tracked replica.
now = time.time()
for replica in self._replicas.get():

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.

instead of gating each replica with RAY_SERVE_STATUS_GAUGE_REPORT_INTERVAL_S, i think we should gate this entire block. looping over all replicas is not cheap. Better to short circuit before the loop

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Implemented in 3c94770. If we do this, we can no longer short-circuit on if value_changed (emitting the metric before the interval has completed) on a per-replica basis. Any replica state changes could wait up to RAY_SERVE_STATUS_GAUGE_REPORT_INTERVAL_S (10 seconds) before the metric reflects the change. Double-checking, is that really reasonable?

Also dropped the per-replica cache in that commit bc interval_elapsed is essentially always true once we get inside the for loop now, making it pointless to check whether the value changed.

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.

we can revisit this later

self._clear_health_gauge_cache(replica_id)
self._replica_state_cache.pop(replica.replica_id, None)
# Update the replica state gauge to 0 (UNKNOWN)
self.replica_state_gauge.set(0, tags={"replica": replica_id})

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.

nice, good attention to detail :)

Signed-off-by: Peter Nguyen <petern0408@gmail.com>
if (
self._last_replica_state_gauge_refresh_time is None
or now - self._last_replica_state_gauge_refresh_time
>= RAY_SERVE_STATUS_GAUGE_REPORT_INTERVAL_S

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.

i think as a follow up PR we should set RAY_SERVE_STATUS_GAUGE_REPORT_INTERVAL_S=60, 10s is too small and can hurt controller perf

@petern48

Copy link
Copy Markdown
Contributor Author

@abrarsheikh Could we add the go label to the PR, since you approved?

@abrarsheikh abrarsheikh added the go add ONLY when ready to merge, run all tests label Apr 27, 2026
@petern48

petern48 commented May 5, 2026

Copy link
Copy Markdown
Contributor Author

CI's passing now

@abrarsheikh

Copy link
Copy Markdown
Contributor

i have recently learnt about some degradation caused by an explosion in metrics cardinality in the head node. Until that is resolve, let's put this PR on hold. See #63114

@github-actions

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had
any activity for 14 days. It will be closed in another 14 days if no further activity occurs.
Thank you for your contributions.

You can always ask for help on our discussion forum or Ray's public slack channel.

If you'd like to keep this open, just leave any comment, and the stale label will be removed.

@github-actions github-actions Bot added the stale The issue is stale. It will be closed within 7 days unless there are further conversation label May 30, 2026

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 3a63b4b. Configure here.

replica.actor_details.state.to_numeric(),
tags={"replica": replica.replica_id.unique_id},
)
self._last_replica_state_gauge_refresh_time = now

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Empty refresh defers replica metrics

Medium Severity

The periodic ray_serve_replica_state export always updates _last_replica_state_gauge_refresh_time after the loop, even when self._replicas.get() is empty. Because check_and_update_replicas() runs before scaling in the same controller tick, a new deployment can start the interval with no replicas and skip reporting until up to RAY_SERVE_STATUS_GAUGE_REPORT_INTERVAL_S after replicas exist.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3a63b4b. Configure here.

@github-actions github-actions Bot added unstale A PR that has been marked unstale. It will not get marked stale again if this label is on it. and removed stale The issue is stale. It will be closed within 7 days unless there are further conversation labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-contribution Contributed by the community go add ONLY when ready to merge, run all tests observability Issues related to the Ray Dashboard, Logging, Metrics, Tracing, and/or Profiling serve Ray Serve Related Issue unstale A PR that has been marked unstale. It will not get marked stale again if this label is on it.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Serve] Emit replica state over time metric

2 participants