Skip to main content

microvm_warm_pool/
lib.rs

1//! Pre-restored Firecracker microVM pool harness.
2//!
3//! Sits on top of [`microvm_runtime`] and turns a snapshot-restore-then-boot
4//! flow into a hashmap lookup. Acquire wallclock drops from ~150 ms (cold) to
5//! ~10 ms (warm).
6//!
7//! The pool is bucketed by [`StackKey`] (`stack_name`, `version`, `vcpu_count`,
8//! `mem_size_mib`) — different identities are not interchangeable, so each
9//! gets its own queue. A single background refill thread keeps every
10//! registered bucket between `min_depth` and `max_depth` entries, evicts
11//! entries older than `entry_max_age`, and drops entries whose
12//! [`EntryValidator`] reports them unhealthy.
13//!
14//! See [`pool::WarmPool`] for the entry point.
15//!
16//! # Required host environment
17//!
18//! Warm handoff with network rewrite requires Firecracker 1.10+ (the version
19//! that honors `network_interfaces` overrides in `PUT /snapshot/load`). The
20//! pool itself runs anywhere; it is the provider you pass in that needs the
21//! KVM-capable Linux host.
22//!
23//! # Example
24//!
25//! ```no_run
26//! use std::sync::Arc;
27//! use std::time::Duration;
28//! use microvm_runtime::{
29//!     InMemoryVmProvider,
30//!     model::{NetworkInterface, SnapshotRef},
31//! };
32//! use microvm_warm_pool::{
33//!     EntryValidator, StackKey, ValidationResult, WarmPool, WarmPoolConfig,
34//! };
35//!
36//! struct AlwaysHealthy;
37//! impl EntryValidator for AlwaysHealthy {
38//!     fn validate(&self, _vm_id: &str) -> ValidationResult {
39//!         ValidationResult::Healthy
40//!     }
41//! }
42//!
43//! let provider = InMemoryVmProvider::default();
44//! let pool = WarmPool::start(
45//!     provider,
46//!     WarmPoolConfig {
47//!         min_depth: 2,
48//!         max_depth: 4,
49//!         refill_interval: Duration::from_secs(5),
50//!         entry_max_age: Duration::from_secs(600),
51//!     },
52//!     Arc::new(AlwaysHealthy),
53//! );
54//!
55//! let stack = StackKey {
56//!     stack_name: "node20".into(),
57//!     version: "1.4.2".into(),
58//!     vcpu_count: 2,
59//!     mem_size_mib: 512,
60//! };
61//! pool.register(
62//!     stack.clone(),
63//!     SnapshotRef {
64//!         vm_id: "template-vm".into(),
65//!         snapshot_id: "template-snap".into(),
66//!         resume_immediately: true,
67//!         network_overrides: Vec::new(),
68//!     },
69//! );
70//!
71//! // Caller side at acquire time: pop a warm entry, then bring up a
72//! // tenant-specific VM by restoring the same snapshot with the per-tenant
73//! // network override. If `acquire` returns `None`, fall back to cold boot.
74//! if let Some(handle) = pool.acquire(&stack) {
75//!     let _ = handle; // restore with handle.source_snapshot + your overrides
76//! }
77//! ```
78
79pub mod pool;
80pub mod stack_key;
81
82pub use pool::{
83    EntryValidator, ValidationResult, WarmPool, WarmPoolConfig, WarmPoolHandle, WarmPoolMetrics,
84};
85pub use stack_key::StackKey;