[PR #182] feat(pool): decay warm-process refill target after idle TTL #235

Open
opened 2026-10-29 14:21:19 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/kvcache-ai/AgentENV/pull/182
Author: @epicvinny
Created: 8/18/2026
Status: 🔄 Open

Base: main ← Head: upstream/warm-pool-idle-ttl


📝 Commits (8)

  • f5b3637 feat(pool): decay warm-process refill target after idle TTL
  • 00784ce fix(pool): persist idle decay state and normalize zero idle TTL
  • 2d4412f fix(pool): compute idle decay from one synchronized demand state
  • ffdedf5 fix(pool): re-validate maintenance drains against live demand state
  • cebbd99 fix(warm-pool): make acquisition pop and demand record atomic under drain lock order
  • 225c252 fix(warm-pool): complete idle decay when pool is already at the decayed target
  • 1fb7b5a fix(warm-pool): compute maintenance actions from the live pool length under both locks
  • 5acb283 fix(warm-pool): complete idle decay only on a verified at-target pool length

📊 Changes

8 files changed (+718 additions, -80 deletions)

View changed files

📝 config/default.toml (+4 -0)
📝 crates/warm-pool/src/lib.rs (+660 -66)
📝 docs/src/configuration/reference.md (+1 -0)
📝 src/cfg.rs (+12 -0)
📝 src/sandbox/firecracker/pool.rs (+5 -2)
📝 src/sandbox/network/manager.rs (+31 -8)
📝 storage/ublk-daemon/src/main.rs (+2 -0)
📝 storage/ublk-daemon/src/server.rs (+3 -4)

📄 Description

What

Adds PoolConfig::idle_ttl to the warm-pool crate: when no warm-process acquisition happens within the TTL, the maintenance worker decays the geometric refill target back to the low watermark and drains the excess warm entries. Wired as [pool.firecracker] idle_ttl_secs (default 600, 0 disables decay).

Why

The pool's fill target only ever ratchets up on acquisitions, so a single burst pins the excess warm Firecracker processes, and the memory they hold, for the lifetime of the server. On bursty shared hosts (business-hours sandbox creation, idle overnight) this wastes memory with no recourse short of restarting the server.

Closes #180

Scope and non-goals

  • Included: idle-TTL decay of the refill target and drain in warm-pool, config plumbing (idle_ttl_secs), docs (config/default.toml, configuration reference), unit tests.
  • Excluded (non-goals from #180): changing the geometric growth policy; per-entry TTL for parked processes; applying decay to the network-slot or ublk pools (they keep idle_ttl: None since they hold no guest processes).

Design and behavior changes

  • The maintenance loop tracks the last-acquisition instant and wakes on the TTL boundary.
  • On expiry, the fill target decays toward the configured low watermark and the excess parked entries are drained through the existing drain path.
  • Any acquisition resets the idle clock, so busy pools never decay.
  • idle_ttl_secs = 0 preserves the exact previous ratchet behavior.

Compatibility and operations

  • Public API or generated protocol: N/A, no API change.
  • Configuration or defaults: new optional key [pool.firecracker] idle_ttl_secs (default 600). Old builds ignore the key. Operators wanting the historical behavior set 0.
  • Snapshot manifest, artifact layout, or storage format: N/A.
  • Upgrade and rollback: safe both ways; rollback simply ignores the new key.
  • Host requirements, permissions, ports, or dependencies: N/A.

Validation

  • make fmt (via cargo fmt --check)
  • make clippy (via cargo clippy -p warm-pool)
  • make test-unit (scoped: cargo test -p warm-pool, 16 passed, incl. 3 new)
  • Relevant Rust integration tests
  • make -C services test (required when services/ changes)
  • Generated clients/server regenerated with the documented make target
  • Documentation updated
  • Benchmarks or performance comparison completed

Commands and results:

cargo fmt --check         # clean
cargo clippy -p warm-pool # clean
cargo test -p warm-pool   # test result: ok. 16 passed; 0 failed
# new tests:
#   idle_ttl_decays_fill_target_and_drains_to_low_watermark
#   maintenance_worker_wakes_on_idle_ttl_and_drains
#   acquisitions_reset_idle_ttl_clock

Skipped checks and reasons: integration tests require root and /dev/kvm, not available on the Windows dev box where this was written. The behavior has also been validated on our staging fleet (GKE KVM nodes) via the fork build.

Risks and reviewer notes

  • Default 600s means existing deployments gain decay on upgrade. If reviewers prefer opt-in, I can flip the default to 0.
  • Review focus: crates/warm-pool/src/lib.rs (TTL bookkeeping in the maintenance loop) and src/cfg.rs (config wiring).

Checklist

  • The PR contains one coherent change and no unrelated formatting or refactoring.
  • New behavior is covered by tests, or I explained why testing is impractical.
  • Logs and examples contain no credentials, tokens, or private registry information.
  • I did not manually edit generated code without updating its source and regenerating it.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/kvcache-ai/AgentENV/pull/182 **Author:** [@epicvinny](https://github.com/epicvinny) **Created:** 8/18/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `upstream/warm-pool-idle-ttl` --- ### 📝 Commits (8) - [`f5b3637`](https://github.com/kvcache-ai/AgentENV/commit/f5b36376d999cb3322bcc8974b6774197f7b3688) feat(pool): decay warm-process refill target after idle TTL - [`00784ce`](https://github.com/kvcache-ai/AgentENV/commit/00784ce311ab2084120436fffbf3e923f3a3ed26) fix(pool): persist idle decay state and normalize zero idle TTL - [`2d4412f`](https://github.com/kvcache-ai/AgentENV/commit/2d4412f252b433a14fda6f2c65b3353af9964df2) fix(pool): compute idle decay from one synchronized demand state - [`ffdedf5`](https://github.com/kvcache-ai/AgentENV/commit/ffdedf54372732ecc869413e87168887070e1516) fix(pool): re-validate maintenance drains against live demand state - [`cebbd99`](https://github.com/kvcache-ai/AgentENV/commit/cebbd99876f9d7c23f874942de81f906fd9e7464) fix(warm-pool): make acquisition pop and demand record atomic under drain lock order - [`225c252`](https://github.com/kvcache-ai/AgentENV/commit/225c252d52627b4e8f73a7be9cf4dcde05ce9ab3) fix(warm-pool): complete idle decay when pool is already at the decayed target - [`1fb7b5a`](https://github.com/kvcache-ai/AgentENV/commit/1fb7b5aa3ba4cba2a358c80604b5ff6d71c19581) fix(warm-pool): compute maintenance actions from the live pool length under both locks - [`5acb283`](https://github.com/kvcache-ai/AgentENV/commit/5acb28388e6933e76a66c35d7c330b9972d8f9d8) fix(warm-pool): complete idle decay only on a verified at-target pool length ### 📊 Changes **8 files changed** (+718 additions, -80 deletions) <details> <summary>View changed files</summary> 📝 `config/default.toml` (+4 -0) 📝 `crates/warm-pool/src/lib.rs` (+660 -66) 📝 `docs/src/configuration/reference.md` (+1 -0) 📝 `src/cfg.rs` (+12 -0) 📝 `src/sandbox/firecracker/pool.rs` (+5 -2) 📝 `src/sandbox/network/manager.rs` (+31 -8) 📝 `storage/ublk-daemon/src/main.rs` (+2 -0) 📝 `storage/ublk-daemon/src/server.rs` (+3 -4) </details> ### 📄 Description ## What Adds `PoolConfig::idle_ttl` to the `warm-pool` crate: when no warm-process acquisition happens within the TTL, the maintenance worker decays the geometric refill target back to the low watermark and drains the excess warm entries. Wired as `[pool.firecracker] idle_ttl_secs` (default 600, `0` disables decay). ## Why The pool's fill target only ever ratchets up on acquisitions, so a single burst pins the excess warm Firecracker processes, and the memory they hold, for the lifetime of the server. On bursty shared hosts (business-hours sandbox creation, idle overnight) this wastes memory with no recourse short of restarting the server. ## Related issue Closes #180 ## Scope and non-goals - Included: idle-TTL decay of the refill target and drain in `warm-pool`, config plumbing (`idle_ttl_secs`), docs (`config/default.toml`, configuration reference), unit tests. - Excluded (non-goals from #180): changing the geometric growth policy; per-entry TTL for parked processes; applying decay to the network-slot or ublk pools (they keep `idle_ttl: None` since they hold no guest processes). ## Design and behavior changes - The maintenance loop tracks the last-acquisition instant and wakes on the TTL boundary. - On expiry, the fill target decays toward the configured low watermark and the excess parked entries are drained through the existing drain path. - Any acquisition resets the idle clock, so busy pools never decay. - `idle_ttl_secs = 0` preserves the exact previous ratchet behavior. ## Compatibility and operations - Public API or generated protocol: N/A, no API change. - Configuration or defaults: new optional key `[pool.firecracker] idle_ttl_secs` (default 600). Old builds ignore the key. Operators wanting the historical behavior set `0`. - Snapshot manifest, artifact layout, or storage format: N/A. - Upgrade and rollback: safe both ways; rollback simply ignores the new key. - Host requirements, permissions, ports, or dependencies: N/A. ## Validation - [x] `make fmt` (via `cargo fmt --check`) - [x] `make clippy` (via `cargo clippy -p warm-pool`) - [x] `make test-unit` (scoped: `cargo test -p warm-pool`, 16 passed, incl. 3 new) - [ ] Relevant Rust integration tests - [ ] `make -C services test` (required when `services/` changes) - [ ] Generated clients/server regenerated with the documented `make` target - [x] Documentation updated - [ ] Benchmarks or performance comparison completed Commands and results: ```text cargo fmt --check # clean cargo clippy -p warm-pool # clean cargo test -p warm-pool # test result: ok. 16 passed; 0 failed # new tests: # idle_ttl_decays_fill_target_and_drains_to_low_watermark # maintenance_worker_wakes_on_idle_ttl_and_drains # acquisitions_reset_idle_ttl_clock ``` Skipped checks and reasons: integration tests require root and `/dev/kvm`, not available on the Windows dev box where this was written. The behavior has also been validated on our staging fleet (GKE KVM nodes) via the fork build. ## Risks and reviewer notes - Default 600s means existing deployments gain decay on upgrade. If reviewers prefer opt-in, I can flip the default to `0`. - Review focus: `crates/warm-pool/src/lib.rs` (TTL bookkeeping in the maintenance loop) and `src/cfg.rs` (config wiring). ## Checklist - [x] The PR contains one coherent change and no unrelated formatting or refactoring. - [x] New behavior is covered by tests, or I explained why testing is impractical. - [x] Logs and examples contain no credentials, tokens, or private registry information. - [x] I did not manually edit generated code without updating its source and regenerating it. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kvcache-ai/AgentENV#235
No description provided.