mirror of
https://github.com/kvcache-ai/AgentENV.git
synced 2026-11-05 01:17:36 +00:00
[PR #414] fix: leave time for graceful shutdown when draining a node #416
Labels
No labels
bug
documentation
enhancement
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/AgentENV#416
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/kvcache-ai/AgentENV/pull/414
Author: @dushulin
Created: 10/22/2026
Status: 🔄 Open
Base:
main← Head:fix/shutdown-drain-budget📝 Commits (2)
75f021cfix(orchestrator): pause sandboxes concurrently during shutdown5619497fix(k8s): cap the preStop drain to leave time for graceful shutdown📊 Changes
3 files changed (+90 additions, -36 deletions)
View changed files
📝
deploy/k8s/base/agentenv-daemonset.yaml(+10 -0)📝
src/orchestrator/service.rs(+43 -36)📝
src/orchestrator/tests.rs(+37 -0)📄 Description
What
Make sure a draining node leaves the server enough time to finish its graceful shutdown:
deploy/k8s/base: the preStop drain loop stops waiting after 3000s, leaving 600s of the 3600sterminationGracePeriodSecondsto the server's SIGTERM shutdown.run_shutdown_cleanup: preserve (pause / delete / wait for) sandboxes with bounded concurrency (8) instead of one at a time.Why
Today a busy node is usually SIGKILLed in the middle of its graceful shutdown:
GET /sandboxesreports 0. Sandboxes with a timeout longer than the grace period keep it running for the whole 3600s. kubelet then grants a one-off 2s extension, sends SIGTERM, and SIGKILLs 2s later.run_shutdown_cleanupawaits each pause before starting the next, so the time needed grows linearly with the number of running sandboxes.UblkDeviceManager::global().shutdown_daemon()only runs after it returns.SIGKILL takes out the whole container cgroup. Sandboxes that were not paused yet are never persisted, and
uvm-ublk-daemondies with its ublk devices still open by Firecracker. That skips the graceful daemon shutdown from #266 / #335, and on kernels without torvalds/linux@f40139fde5 it can crash the host. Details in #413.Related issue
Closes #413
Scope and non-goals
Included:
deploy/k8s/base/agentenv-daemonset.yaml.run_shutdown_cleanup, plus a unit test.Not included:
terminationGracePeriodSecondsin the same manifest, and the concurrency is a constant.Schedule.Design and behavior changes
preStop
deadline = now + 3000, checked at the top of each iteration.preStop: drain deadline reached, leaving remaining sandboxes to graceful shutdownand exits. kubelet then sends SIGTERM, and the server pauses and persists what is left.run_shutdown_cleanupfutures::stream::iter(..).buffer_unordered(8)and collects the failures.Compatibility and operations
terminationGracePeriodSecondsshould keep the deadline below it, with enough margin for their sandbox count.futuresis already a dependency of the crate.Validation
make fmt(rancargo fmt --all -- --check)make clippy(ran for the touched crate only, see below)make test-unitmake -C services test(required whenservices/changes)maketargetCommands and results:
New test:
orchestrator::service::tests::shutdown_pauses_running_sandboxes_concurrently.shutdown()finishes in less than 2 pause durations and that all sandboxes end upPaused.4 pauses should overlap, took 40s.The preStop snippet was run under
dash(the runtime image's/bin/sh) against a local fake API with the deadline lowered to a few seconds:Skipped checks and reasons:
make clippy/make test-unitcover more crates than this change touches; I ran clippy and the orchestrator unit tests foragentenvonly.Risks and reviewer notes
8 × 600s / pause timesandboxes. I did not add a knob, since the manifest is the place to tune both numbers together.src/orchestrator/service.rs(run_shutdown_cleanup) anddeploy/k8s/base/agentenv-daemonset.yaml.service.rs/tests.rs, but in the resume path. It should not conflict textually.Checklist
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.