Skip to content

[History Server] Treat suspended RayCluster as dead in isDead - #5069

Open
yjaw wants to merge 3 commits into
ray-project:masterfrom
yjaw:fix/historyserver-suspended-raycluster-live-check
Open

[History Server] Treat suspended RayCluster as dead in isDead#5069
yjaw wants to merge 3 commits into
ray-project:masterfrom
yjaw:fix/historyserver-suspended-raycluster-live-check

Conversation

@yjaw

@yjaw yjaw commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Why are these changes needed?

When a RayCluster is suspended (spec.suspend = true), KubeRay deletes all Pods (including the head Pod) but keeps the RayCluster CR. The history server had multiple places that treated "the RayCluster CR exists" as "the cluster is live," none of which accounted for suspension, so it kept trying to proxy dashboard requests to a head Pod that no longer exists — failing with a DNS lookup error — and neither the live nor the dead session for that cluster could be viewed.

SessionProcessor.isDead

Only checked whether the CR existed. Now also treats a suspended RayCluster as dead so its sessions fall back to reading stored historical data.

We check the RayClusterSuspended status condition rather than spec.Suspend directly: spec.Suspend flips true the instant a user requests suspension, well before Pods are actually deleted. Marking the session dead (and caching its snapshot — dead-session snapshots are cached indefinitely) at that point would race the collector's SIGTERM-triggered flush of the final logs/events, permanently caching an incomplete snapshot. RayClusterSuspended is only set by the controller once it observes zero running Pods (raycluster_controller.go#L2064-L2083), which is after the flush window has passed. During the brief RayClusterSuspending transition, the session is still treated as live and a proxy attempt can transiently fail, but SessionStatusLive is never cached, so the next request re-checks and resolves automatically — no permanent breakage.

listClusters and resolveSession

isDead alone wasn't sufficient: listClusters (used to build the cluster list) and resolveSession (used to resolve /enter_cluster/... requests, including the default "latest" resolution — the primary path a user hits when opening a cluster) each independently call into the K8s client and treat any existing RayCluster CR as live, bypassing isDead entirely. A suspended cluster was still shown as a live entry in the list, and entering it still resolved to "live" and proxied to a Pod that no longer exists.

Extracted isRayClusterSuspended as a shared helper (used by isDead too) and applied it in both places so a suspended cluster is excluded from the live list and falls back to stored session data when resolved.

Related issue number

Closes #5062

Labels

  • If this PR has user-facing changes that require documentation updates at release time, I have added the doc-updates-required label.
  • If this PR contains breaking changes, I have added the breaking-change label.

Checks

  • I've made sure the tests are passing.
  • Testing Strategy
    • Unit tests
    • Manual tests
    • This PR is not tested :(

yjaw added 2 commits August 2, 2026 05:05
A suspended RayCluster keeps its CR but deletes all Pods, so proxying
to the head service fails. Check spec.suspend in isDead so sessions
fall back to stored historical data instead.

Close ray-project#5062
…spend

spec.Suspend flips true the instant a user requests suspension, well
before Pods are actually terminated. isDead would mark the session dead
and cache its snapshot immediately, racing the collector's SIGTERM flush
and permanently caching incomplete data.

RayClusterSuspended is only set once the controller observes zero
running Pods, so the flush window has already passed by the time we
treat the session as dead and cacheable.

@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 7eb847e. Configure here.

Comment thread historyserver/pkg/historyserver/session_processor.go
…Session

isDead alone wasn't enough: listClusters and resolveSession independently
treat any existing RayCluster CR as live, bypassing isDead entirely. Since
resolveSession backs the primary /enter_cluster entry point (including the
default "latest" resolution), a suspended cluster was still shown as live
and still proxied to a head Pod that no longer exists.

Extract isRayClusterSuspended as a shared helper and apply it in both
places so a suspended cluster falls back to stored session data instead.
@win5923

win5923 commented Aug 3, 2026

Copy link
Copy Markdown
Member

Hi @yjaw, thanks for addressing this issue so quickly! As @chiayi mentioned, we’ll wait until after 1.7 to address this.

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.

[History Server] When spec.suspend = true, the data for both live and dead clusters is unavailable.

2 participants