Skip to content

[Serve] Base handle metric staleness on controller receive time - #66307

Merged
abrarsheikh merged 3 commits into
ray-project:masterfrom
dundysm:fix/serve-handle-metrics-receive-time-66271
Sep 22, 2026
Merged

abrarsheikh merged 3 commits into
ray-project:masterfrom
dundysm:fix/serve-handle-metrics-receive-time-66271

Conversation

@dundysm

@dundysm dundysm commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Fixes

Fixes #66271

Problem

drop_stale_handle_metrics is documented as dropping handles the controller has not received updates from within max(2 * metrics_interval_s, RAY_SERVE_MIN_HANDLE_METRICS_TIMEOUT_S), but it compared controller time.time() to the producer's report.timestamp. That mixes wall clocks from different machines, so skew can drop fresh metrics early (producer behind) or retain phantoms past the timeout (producer ahead).

What changes

  • _HandleMetricStore records a controller-local monotonic receive time in _received_at when accept() succeeds.
  • drop_stale_handle_metrics ages handles as time.monotonic() - received_at for the timeout path.
  • forget() clears _received_at with the rest of the handle state.
  • Rejected (stale) accepts do not refresh receive time.

What is preserved (intentional)

  • Producer timestamps remain the sole key for is_fresher / cross-format ordering ([serve] Columnar zero-copy autoscaling-metrics ingest (plumbing) #66070).
  • Timeseries sample timestamps and aggregation look-back stay producer-based.
  • Ingest-delay metrics (_record_metrics_delay) stay producer-based.
  • Dead Serve-actor dropping is unchanged.
  • No wire / public API change; receive time is never put on the wire.

This is scoped only to the drop freshness mismatch with the documented "received" semantics. Aggregation last_window_s skew and delay-metric docs are left alone on purpose.

Tests

  • New unit coverage for producer clock behind/ahead, rejected accept not refreshing receive time, fresher accept refreshing it, dead-actor path, and columnar parity.
  • Existing columnar drop / fresher / cross-format tests updated so timeout cases patch time.monotonic alongside time.time.
  • mock_deployment_state_manager also patches time.monotonic so handle-timeout deployment-state tests keep working.

Related

Credit to @suppagoddo for the issue writeup and receive-time approach. Coordinates with #66070 (ordering gate) and does not wait on #66240.

cc @ray-project/ray-serve @edoakes @zcin @johntaylor-cell @suppagoddo

drop_stale_handle_metrics treated producer report.timestamp as receive
age, so clock skew between routers and the controller could drop fresh
metrics early or retain phantoms past the timeout.

Record a controller-local monotonic receive time in _HandleMetricStore
on accepted reports and use that only for the timeout path. Keep
producer timestamps for is_fresher / cross-format ordering, timeseries
aggregation, and ingest-delay metrics. Dead-actor dropping is unchanged.

Fixes ray-project#66271

Signed-off-by: Dundy Pasupuleti <dundysm@gmail.com>
@dundysm
dundysm requested a review from a team as a code owner September 18, 2026 23:22
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@dundysm

dundysm commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

cc @ray-project/ray-serve @edoakes @zcin @johntaylor-cell @suppagoddo

approach a from the issue: controller-local monotonic receive time for drop_stale_handle_metrics only. producer timestamps stay for is_fresher / cross-format ordering (#66070), timeseries, and ingest-delay metrics. dead-actor path unchanged.

fixes #66271

@ray-gardener ray-gardener Bot added serve Ray Serve Related Issue community-contribution Contributed by the community labels Sep 19, 2026
@suppagoddo

Copy link
Copy Markdown
Contributor

@dundysm - Can you fix the failing tests?

@johntaylor-cell johntaylor-cell 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.

Thank you for this. Verified. Only the attached diff is needed to pass lint

@johntaylor-cell

Copy link
Copy Markdown
Contributor

ray-66307-minimal.txt

@abrarsheikh

Copy link
Copy Markdown
Contributor

pre-commit checks are failing

@johntaylor-cell johntaylor-cell added the go add ONLY when ready to merge, run all tests label Sep 22, 2026
Apply @johntaylor-cell minimal patch: black/isort formatting in
test_columnar.py and conftest.py, plus treat missing receive stamps as
timed out in drop_stale_handle_metrics so a broken invariant cannot keep
handles forever. accept() always stamps _received_at; forget() clears it,
so the None path is defensive only.

Signed-off-by: Dundy Pasupuleti <dundysm@gmail.com>
@dundysm

dundysm commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

@abrarsheikh applied @johntaylor-cell's minimal lint patch (black/isort wraps plus the defensive timed_out None receive-stamp handling in drop_stale_handle_metrics) and pushed to this branch. please re-check pre-commit.

@dundysm

dundysm commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

@johntaylor-cell thanks for the verify, approval, and minimal diff. applied and pushed as-is. the timed_out None change is intentional defensive only: accept() always stamps _received_at after the fresher gate, and forget() clears it, so the happy path is unchanged.

@abrarsheikh
abrarsheikh merged commit 5f812e8 into ray-project:master Sep 22, 2026
6 checks passed
owenowenisme pushed a commit to owenowenisme/ray that referenced this pull request Sep 23, 2026
…project#66307)

## Fixes

Fixes ray-project#66271

## Problem

`drop_stale_handle_metrics` is documented as dropping handles the
controller has not **received** updates from within `max(2 *
metrics_interval_s, RAY_SERVE_MIN_HANDLE_METRICS_TIMEOUT_S)`, but it
compared controller `time.time()` to the producer's `report.timestamp`.
That mixes wall clocks from different machines, so skew can drop fresh
metrics early (producer behind) or retain phantoms past the timeout
(producer ahead).

## What changes

- `_HandleMetricStore` records a controller-local **monotonic** receive
time in `_received_at` when `accept()` succeeds.
- `drop_stale_handle_metrics` ages handles as `time.monotonic() -
received_at` for the timeout path.
- `forget()` clears `_received_at` with the rest of the handle state.
- Rejected (stale) accepts do **not** refresh receive time.

## What is preserved (intentional)

- Producer timestamps remain the sole key for `is_fresher` /
cross-format ordering (ray-project#66070).
- Timeseries sample timestamps and aggregation look-back stay
producer-based.
- Ingest-delay metrics (`_record_metrics_delay`) stay producer-based.
- Dead Serve-actor dropping is unchanged.
- No wire / public API change; receive time is never put on the wire.

This is scoped only to the drop freshness mismatch with the documented
"received" semantics. Aggregation `last_window_s` skew and delay-metric
docs are left alone on purpose.

## Tests

- New unit coverage for producer clock behind/ahead, rejected accept not
refreshing receive time, fresher accept refreshing it, dead-actor path,
and columnar parity.
- Existing columnar drop / fresher / cross-format tests updated so
timeout cases patch `time.monotonic` alongside `time.time`.
- `mock_deployment_state_manager` also patches `time.monotonic` so
handle-timeout deployment-state tests keep working.

## Related

Credit to @suppagoddo for the issue writeup and receive-time approach.
Coordinates with ray-project#66070 (ordering gate) and does not wait on ray-project#66240.

cc @ray-project/ray-serve @edoakes @zcin @johntaylor-cell @suppagoddo

---------

Signed-off-by: Dundy Pasupuleti <dundysm@gmail.com>
Co-authored-by: Abrar Sheikh <abrar@anyscale.com>
nadongjun pushed a commit to nadongjun/ray that referenced this pull request Oct 6, 2026
…project#66307)

## Fixes

Fixes ray-project#66271

## Problem

`drop_stale_handle_metrics` is documented as dropping handles the
controller has not **received** updates from within `max(2 *
metrics_interval_s, RAY_SERVE_MIN_HANDLE_METRICS_TIMEOUT_S)`, but it
compared controller `time.time()` to the producer's `report.timestamp`.
That mixes wall clocks from different machines, so skew can drop fresh
metrics early (producer behind) or retain phantoms past the timeout
(producer ahead).

## What changes

- `_HandleMetricStore` records a controller-local **monotonic** receive
time in `_received_at` when `accept()` succeeds.
- `drop_stale_handle_metrics` ages handles as `time.monotonic() -
received_at` for the timeout path.
- `forget()` clears `_received_at` with the rest of the handle state.
- Rejected (stale) accepts do **not** refresh receive time.

## What is preserved (intentional)

- Producer timestamps remain the sole key for `is_fresher` /
cross-format ordering (ray-project#66070).
- Timeseries sample timestamps and aggregation look-back stay
producer-based.
- Ingest-delay metrics (`_record_metrics_delay`) stay producer-based.
- Dead Serve-actor dropping is unchanged.
- No wire / public API change; receive time is never put on the wire.

This is scoped only to the drop freshness mismatch with the documented
"received" semantics. Aggregation `last_window_s` skew and delay-metric
docs are left alone on purpose.

## Tests

- New unit coverage for producer clock behind/ahead, rejected accept not
refreshing receive time, fresher accept refreshing it, dead-actor path,
and columnar parity.
- Existing columnar drop / fresher / cross-format tests updated so
timeout cases patch `time.monotonic` alongside `time.time`.
- `mock_deployment_state_manager` also patches `time.monotonic` so
handle-timeout deployment-state tests keep working.

## Related

Credit to @suppagoddo for the issue writeup and receive-time approach.
Coordinates with ray-project#66070 (ordering gate) and does not wait on ray-project#66240.

cc @ray-project/ray-serve @edoakes @zcin @johntaylor-cell @suppagoddo

---------

Signed-off-by: Dundy Pasupuleti <dundysm@gmail.com>
Co-authored-by: Abrar Sheikh <abrar@anyscale.com>
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 serve Ray Serve Related Issue

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Serve] Handle freshness depends on clocks from different machines

4 participants