Skip to content

[Core] Debug lineage reconstruction miss on spilled objects - #65660

Merged
rueian merged 3 commits into
ray-project:masterfrom
Kunchd:lineage_reconstruction_with_spill
Sep 25, 2026
Merged

rueian merged 3 commits into
ray-project:masterfrom
Kunchd:lineage_reconstruction_with_spill

Conversation

@Kunchd

@Kunchd Kunchd commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor

Description

Through a recent investigation in object fetch time out errors, we have uncovered a scenario where lineage reconstruction may fail to trigger due to a race between node death notification and object spilled notification.

Currently when objects are spilled, a spill notification is sent to the owner. However, an out of date spill notification for a dead node can actually corrupt the owner's reference counting state, leading to lineage reconstruction failing to trigger when the object is lost further down the line.

Consider the following diagram:
image

At a high level, the following sequence occurs.

  1. A produced object is spilled on the first executing node, and a message is sent to the object owner to notify it about the spill. This message is delayed.
  2. The node shortly after goes down, and the GCS picks up on this.
  3. The GCS then sends a signal and is received by the object owner. The owner upon learning about the node death, clears the object's tracking metadata and trigger lineage reconstruction.
  4. Reconstruction executes on another node and eventually completes.
  5. At this point the spill notification finally arrives. The mechanisms that currently protects the reference counter from stale spill messages actually sets spilled to true even though the node is dead. Additionally, the new pinned object location is also cleared via UnsetObjectPrimaryCopy, corrupting the owner's state. (Eluded in the diagram for cleanliness, but at this point another reconstruction attempt is triggered. This reconstruction attempt sees that the spilled flag is true and assumes the object is still within the cluster so it stops).
  6. The reconstructed object is lost again via node death.
  7. The GCS again notify the owner about the node death. However, this time, when the owner attempts to trigger reconstruction this time around, because its state is corrupted (no pinned primary copy or spilled node id), no reconstruction is ever triggered.

This ultimately results in ObjectFetchTimeOut error.

What this PR does

This PR introduces a check within HandleObjectSpilled that make sure we only update the spilled object metadata if the node we spilled is actually still alive, avoiding corrupting the owner state with the spill information of a dead node.

Related issues

Additional information

Signed-off-by: davik <davik@anyscale.com>
@Kunchd
Kunchd requested a review from a team as a code owner August 22, 2026 00:41

@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 addresses an issue where a stale spill report from a dead node could poison an object's location state and prevent future reconstructions. It ensures that the spilled flag is only set if the spilled location is alive, and only clears the pinned copy if the spilled node matches the pinned node. A regression test has been added to verify this behavior. The reviewer suggested a performance improvement to avoid redundant recovery attempts by only pushing the object to objects_to_recover_ when the pinned copy is actually cleared.

@Kunchd Kunchd added the go add ONLY when ready to merge, run all tests label Aug 22, 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 139da33. Configure here.

@ray-gardener ray-gardener Bot added the core Issues that should be addressed in Ray Core label Aug 22, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

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 Sep 7, 2026
@Kunchd Kunchd added stale The issue is stale. It will be closed within 7 days unless there are further conversation and removed stale The issue is stale. It will be closed within 7 days unless there are further conversation labels Sep 15, 2026
@Yicheng-Lu-llll Yicheng-Lu-llll self-assigned this Sep 22, 2026
@rueian
rueian merged commit 3133faf into ray-project:master Sep 25, 2026
6 checks passed
@Kunchd
Kunchd deleted the lineage_reconstruction_with_spill branch September 26, 2026 19:59
nadongjun pushed a commit to nadongjun/ray that referenced this pull request Oct 6, 2026
…ect#65660)

## Description
Through a recent investigation in object fetch time out errors, we have
uncovered a scenario where lineage reconstruction may fail to trigger
due to a race between node death notification and object spilled
notification.

Currently when objects are spilled, a spill notification is sent to the
owner. However, an out of date spill notification for a dead node can
actually corrupt the owner's reference counting state, leading to
lineage reconstruction failing to trigger when the object is lost
further down the line.

Consider the following diagram:
<img width="3560" height="1315" alt="image"
src="https://github.com/user-attachments/assets/e5dd9128-2411-448c-b148-359ef7d7f35b"
/>

At a high level, the following sequence occurs. 
1. A produced object is spilled on the first executing node, and a
message is sent to the object owner to notify it about the spill. This
message is delayed.
2. The node shortly after goes down, and the GCS picks up on this. 
3. The GCS then sends a signal and is received by the object owner. The
owner upon learning about the node death, clears the object's tracking
metadata and trigger lineage reconstruction.
4. Reconstruction executes on another node and eventually completes.
5. At this point the spill notification finally arrives. The mechanisms
that currently protects the reference counter from stale spill messages
actually sets `spilled` to true even though the node is dead.
Additionally, the new pinned object location is also cleared via
`UnsetObjectPrimaryCopy`, corrupting the owner's state. (Eluded in the
diagram for cleanliness, but at this point another reconstruction
attempt is triggered. This reconstruction attempt sees that the spilled
flag is true and assumes the object is still within the cluster so it
stops).
6. The reconstructed object is lost again via node death.
7. The GCS again notify the owner about the node death. However, this
time, when the owner attempts to trigger reconstruction this time
around, because its state is corrupted (no pinned primary copy or
spilled node id), no reconstruction is ever triggered.

This ultimately results in `ObjectFetchTimeOut` error.

### What this PR does
This PR introduces a check within `HandleObjectSpilled` that make sure
we only update the spilled object metadata if the node we spilled is
actually still alive, avoiding corrupting the owner state with the spill
information of a dead node.

## Related issues

## Additional information

Signed-off-by: davik <davik@anyscale.com>
Co-authored-by: davik <davik@anyscale.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Issues that should be addressed in Ray Core go add ONLY when ready to merge, run all tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants