Skip to content

atelet: Clean up whole actor directory on detach - #2871

Merged
Michelle Au (msau42) merged 1 commit into
agent-substrate:mainfrom
sairajp-rewind:cleanup-actor-dir-on-detach
Oct 21, 2026
Merged

Michelle Au (msau42) merged 1 commit into
agent-substrate:mainfrom
sairajp-rewind:cleanup-actor-dir-on-detach

Conversation

@sairajp-rewind

@sairajp-rewind Sairaj Pokale (sairajp-rewind) commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

What this PR does and why we need it ?

When detaching an actor (either via background timer detach or explicit DetachActor RPC), atelet previously only pruned entries inside /var/lib/ate/snapshots/<uid>/local-checkpoint/, leaving the actor's snapshot directory (/var/lib/ate/snapshots/<uid>) and actor directory (/var/lib/ate/actors/<uid>) on the node indefinitely. Because sandbox-assets/ holds hard links into the sandbox asset cache (st_nlink > 1), leaving the actor directory also permanently pinned sandbox binaries in the cache after detach.

Changes

  • Move ResetDir, ResetActorDirs, ResetActorDirsKeepingVolumes, RemoveActorFilesExceptState, and RemoveActorDirs into cmd/atelet/internal/actordirs so Atelet and snapshottracker.Tracker share directory cleanup logic (preserving populated external volume mount directories, removing ateletpath.ActorSnapshotPath, and handling read-only bundle upper directories via imagecache.RemoveAllWritable).
  • Update Tracker.finishDetach to call actordirs.RemoveActorFilesExceptState (removing /var/lib/ate/snapshots/<uid> and all entries under /var/lib/ate/actors/<uid> except snapshot-state.json) while opDetach is active, and mark a detach report due (markReportDueLocked) for both background and foreground Detach calls.
  • Keep snapshot-state.json (with ReportDueSince) on disk until the detach report finishes so a retried DetachActor RPC still sees LatestDurable and a pending detach report survives an atelet restart.
  • Remove snapshot-state.json and the empty /var/lib/ate/actors/<uid> directory (via removeDetachedActorState in finishReportDueLocked) once !Started && LatestLocal == nil && Uploading == nil and the control plane acknowledges the detach report or refuses it with NotFound. On give-up or any other refusal (Unimplemented, FailedPrecondition, InvalidArgument), snapshot-state.json stays on disk with ReportDueSince cleared so DetachActor keeps returning LatestDurable.
  • Require --snapshot-report-workers >= 1 in validateSnapshotWorkerFlags so background detach reports are always sent.
  • In cleanUpAfterCheckpoint, call actordirs.RemoveActorFilesExceptState instead of actordirs.ResetActorDirs when no local snapshot is kept on the node, so empty subdirectories are not recreated.
  • Document in atelet.proto (ActorSnapshotState.latest_durable and DetachActorResponse.state) that DetachActor queues a background detach report and forgets the actor once acknowledged.

Merge order: Land after #2797 so Terminate tolerates a missing sandbox-assets.json after cleanUpAfterCheckpoint calls RemoveActorFilesExceptState.

  • Tests pass
  • Appropriate changes to documentation are included in the PR

@igooch igooch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm for removing the whole directory at detach. I have one question inline, and two small asks here.

Please say in the PR description what happens to a pending detach report when atelet restarts. Today the report is saved in snapshot-state.json, so it survives a restart. With this PR it lives only in memory. That may be fine, but the description should say so. The inline comment has the details.

Please update the DetachActorResponse comment in atelet.proto. It says latest_durable is set "if atelet knows one". After this PR, atelet forgets the actor once the detach report is sent, so calling DetachActor again returns an empty state. #2598 will call DetachActor, and it needs to treat an empty state as already detached.

On merge order with related PRs:

  • If #2772 merges first, drop its removeSandboxAssets call when you rebase, since RemoveActorDirs already deletes that directory. Keep its nlink test. If this PR merges first, #2772 can be closed.
  • If #2746 merges first, RemoveActorDirs also needs to delete /var/lib/ate/snapshots/<uid>/ (ateletpath.ActorSnapshotPath). If this PR merges first, #2746 adds that when it rebases.

Comment thread internal/proto/ateletpb/atelet.proto Resolved
@sairajp-rewind
Sairaj Pokale (sairajp-rewind) force-pushed the cleanup-actor-dir-on-detach branch 3 times, most recently from 5d2f943 to 5a62856 Compare October 21, 2026 16:57

@igooch igooch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Agreed on choice of the Option B shape. I found one bug in the forget path and one merge-order dependency on #2797. Details inline.

@igooch igooch left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤖 Both comments are addressed, thanks.

The new commit message doesn't match the diff. Neither main nor this PR has a RemoveActorData, and it leaves out the actordirs move, the --snapshot-report-workers >= 1 check and the cleanUpAfterCheckpoint change. Could you restore the
previous message and add a line for the !a.Started guard?

Otherwise, looks good on top of #2797.

@sairajp-rewind

Copy link
Copy Markdown
Collaborator Author

🤖 Both comments are addressed, thanks.

The new commit message doesn't match the diff. Neither main nor this PR has a RemoveActorData, and it leaves out the actordirs move, the --snapshot-report-workers >= 1 check and the cleanUpAfterCheckpoint change. Could you restore the previous message and add a line for the !a.Started guard?

Otherwise, looks good on top of #2797.

Addressed!

@sairajp-rewind
Sairaj Pokale (sairajp-rewind) force-pushed the cleanup-actor-dir-on-detach branch 2 times, most recently from 25d59ae to c383eed Compare October 21, 2026 21:03
@sairajp-rewind

Copy link
Copy Markdown
Collaborator Author

Rebased onto main after #2940 (bb41c52), restored the commit message, and updated CommittedCheckpointState to keep a pending detach report due when LatestLocal == nil. Ready to land once #2797 merges.

Comment thread cmd/atelet/lifecycle_test.go Resolved
Move ResetDir, ResetActorDirs, ResetActorDirsKeepingVolumes,
RemoveActorFilesExceptState, and RemoveActorDirs into
cmd/atelet/internal/actordirs so both atelet and snapshottracker can call them.

When Detach runs (or background upload finishes with DeleteLocalOnUpload), call
actordirs.RemoveActorFilesExceptState to delete the actor's snapshot directory
tree and all files and subdirectories under the actor's directory except
snapshot-state.json, refusing to delete through a populated external volume
mount directory. When the detach report is acknowledged or refused with
NotFound and the actor has not started again (!a.Started), delete
snapshot-state.json and remove the empty actor root directory. Keep a pending
detach report due in CommittedCheckpointState when LatestLocal is nil so a
retried Checkpoint after a background detach still cleans up snapshot-state.json
and the actor directory once the detach report completes.

Require --snapshot-report-workers >= 1 in validateSnapshotWorkerFlags and remove
the reporting-disabled detached state removal branch in queueReportLocked and
enqueueSavedReportLocked.

When Checkpoint cleans up with no local snapshot kept on the node (such as
UPLOAD_MODE_IMMEDIATE without a local copy, or a retried Checkpoint after
Detach), call actordirs.RemoveActorFilesExceptState instead of
actordirs.ResetActorDirs so empty subdirectories are not recreated.
@msau42
Michelle Au (msau42) added this pull request to the merge queue Oct 21, 2026
Merged via the queue into agent-substrate:main with commit e4ae7a4 Oct 21, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/node area/storage kind/bug Something isn't working / bugfixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants