Repository navigation
ateapi,atelet: reclaim actor node state when a worker's pod is gone - #2797
Conversation
16fe427 to
fcb4525
Compare
fcb4525 to
10bed3c
Compare
48e086b to
8b56220
Compare
igooch
left a comment
There was a problem hiding this comment.
The ateapi side looks good to me. Taking the actor's lease, and giving up on a node after one timeout, both make sense. I have two questions inline on the keep branch in Terminate, and three asks on the description.
Please fix the PR description so it matches the code.
- The first paragraph says
DeleteWorkerclears the actor'sAssignedNode. It doesn't, and it shouldn't. The crash keepsAssignedNodeso a later delete or revert can still clean up the node, and this PR relies on that when it skips a reclaim. - One bullet says delete and revert no longer skip Terminate when
worker_pod_uidis empty. Main already sends Terminate in that case. The only change here inensureAteletTerminatedis moving the fallback spec intofallbackWorkloadSpec. Please drop the bullet. Fixes #<issue_number_goes_here>is still the placeholder. This is #1688.
#2871 moves resetActorDirs into the snapshottracker package. Whichever of the two PRs merges second needs a one-line rename in the keep branch.
|
Traced both questions against what landed on
Sending a full Does dropping |
Agreed, drop A few asks:
Michelle Au (@msau42), with the full Terminate, an async-suspend snapshot whose successful upload wasn't reported before the crash is lost. That's already true on main, since ateapi refuses the report while CRASHED and revert deletes the PENDING prefix. Is that intended, or should it be recoverable? |
8b56220 to
9aaa731
Compare
|
Thanks @igooch! Rebased onto latest
|
That is fine for now. If the upload had already completed on |
0a87a28 to
9c076b2
Compare
|
@igooch Rebased onto #2746 ( |
igooch
left a comment
There was a problem hiding this comment.
The ateapi side still looks good to me. I have one behavior fix in Terminate and a few small cleanups inline.
5ba10b4 to
193636e
Compare
igooch
left a comment
There was a problem hiding this comment.
🤖 All five comments are addressed, thanks. One test now fails in CI, inline. The description's first bullet also still says Restore writes the record after RestoreWorkload, so please update it to match.
igooch
left a comment
There was a problem hiding this comment.
LGTM.
Michelle Au (@msau42) could you please review?
193636e to
b5f1ebf
Compare
A deleted worker pod is deregistered, and its bound actors are marked CRASHED, but their node state is never terminated, so actors/<uid> and snapshots/<uid> stay on the node until the actor is deleted or reverted, if it ever is. The worker-delete workflow now sends atelet's Terminate before releasing each bound actor. It is best-effort, so an unreachable node cannot wedge deregistration. Each Terminate gets 30s, so a hung unmount cannot run out the delete's deadline. Once one times out or cannot reach atelet, other actors on that node skip Terminate for 30s across subsequent worker deletes and are left to their revert or delete. Each release holds the actor's lease, so it never runs during a suspend. An actor whose lease is taken is left for a retry: DeleteWorker returns ABORTED, which workersync requeues. Terminate now skips workload teardown when the worker is gone (missing socket, no sandbox record, or UNAVAILABLE) while still reclaiming the actor's node state. Restore writes the sandbox record before RestoreWorkload, matching Run, so a missing record means no sandbox was started.
b5f1ebf to
a18d3a6
Compare
## 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 agent-substrate#2797 so `Terminate` tolerates a missing `sandbox-assets.json` after `cleanUpAfterCheckpoint` calls `RemoveActorFilesExceptState`. - [x] Tests pass - [x] Appropriate changes to documentation are included in the PR
What is this PR and Why we need it ?
A deleted worker pod is deregistered by
workersync, which callsDeleteWorkerto mark its assigned actorsCRASHEDand clear theirWorkerAssignment. Those actors are never terminated on the node, so/var/lib/ate/actors/<uid>and/var/lib/ate/snapshots/<uid>stay on disk until the actor is later deleted or reverted, if it ever is. (Note: this covers worker-pod removal viaDeleteWorker; tearing down a crashed sandbox on a still-live worker is tracked separately in #2355.)Changes
ateletworkerless / gone-workerTerminate:TerminateWorkloadwhenworker_pod_uidis empty, the worker socket is gone,sandbox-assets.jsonis absent (RunandRestorewrite it beforeRunWorkload/RestoreWorkload, and an earlierTerminateremoves it with the actor directory), orTerminateWorkloadreturnsUnavailable/NotFound. Any other error from a live worker failsTerminatebefore touching disk.TerminatereturnInternalwithout%w-wrapping downstream gRPC errors, so a transient CSI failure does not surface toateapiasUnavailable(and reachesDeleteActor/RevertActorcallers asInternalinstead ofUnavailable).ateapi(DeleteWorker):DeleteWorkertakes each actor's lease (ABORTEDif held, requeued byworkersync), skips actors that already reachedSUSPENDED, and calls best-effortatelet.Terminatewith a 30s timeout to reclaim the actor's node state and local snapshots. Once a call times out (DeadlineExceeded) or returnsUnavailable, remaining actors on that worker skip the node and leave cleanup to revert/delete.Testing
go test ./cmd/atelet/... ./cmd/ateapi/internal/controlapi/...c3-standard-4gvisornodes, 3 ×c3-highcpu-4microvmnodes):gvisor(3 ×c3-standard-4)microvm(3 ×c3-highcpu-4)durdir_data_baseline1m smoke (8 MiBglutton-durdir-data)20reqs,0fails (0.00%)15reqs,0fails (0.00%)DeleteWorkerscale-down reclaim (3 actors, 256 MiBdurable-dir/actor)/var/lib/ate/actors:0.00 GB -> 1.41 GB (3 dirs) -> 0.00 GB (0 dirs);-0.25 GB/node reclaimed (+0.00 GBvs baseline)/var/lib/ate/actors:0.00 GB -> 1.64 GB (3 dirs) -> 0.00 GB (0 dirs);-0.25 GB/node reclaimed (+0.00 GBvs baseline)DeleteActoron paused actor with no worker (worker_pod_uid="")local-checkpointpruned &/var/lib/ate/actors/<uid>removed (1.75 ms)local-checkpointpruned &/var/lib/ate/actors/<uid>removed (9.45 ms)Fixes #1688