You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* feat(sdk): parallel pipeline fan-out + typed JSON report with metrics
Base::run_parallel runs steps as concurrent copy-on-write MicroVM forks
(bounded, collect-all, input-ordered) and returns a dependency-free JSON
Report. StepResult gains separated stdout/stderr, duration_ms, and metrics
parsed from `::metric <key>=<value>` guest-stdout lines (a scoring channel
for matrix/selection workloads).
Steps now take &self (atomic fork counter), so fan-out no longer needs
hand-rolled threads. RAII removes each fork on every path and the base
snapshot on Drop (--force). Box/snapshot names carry per-process+instance
entropy to prevent cross-pipeline name collisions; output is capped to bound
report memory under large fan-out; infra failures use a distinct sentinel.
15 unit tests + doctest, clippy clean; validated end-to-end on a real
/dev/kvm host (real boot, CoW fork-per-step, metrics, JSON report, 0 leaks).
* test(sdk): real-KVM integration + soak suites; add crash-orphan sweep + infra retry
Backs the parallel pipeline with real-microVM coverage and hardens it for
sustained, highly-concurrent churn:
- sweep_orphans(): reclaim ci-base-* boxes/snapshots left by a SIGKILL/OOM'd
pipeline process (its RAII never ran), matched by the dead owner pid embedded
in the resource name; never touches a live peer's resources.
- WarmBase::infra_retries (default 2): retry a fork that hits a TRANSIENT infra
failure (restore/start/boot); the step's command never ran, so re-forking is
idempotent. Keeps sustained high-concurrency churn green.
- tests/integration_kvm.rs (5 #[ignore] tests): warm+fork+exec, cache hit,
parallel order/metrics, fork isolation, leak-freeness, sweep crash-recovery.
- tests/soak_kvm.rs: sustained fork-eval churn stays leak-free and RSS-stable;
leak gates are process-scoped (robust to a concurrent pipeline on the host).
- ci.yml: run both under the integration-kvm (real /dev/kvm) gate.
Validated on a real KVM host (a3s-box 2.5.1): integration 5/5; soak 1500
fork-evals across 75 generations leak-free, RSS +512 KiB; 0 orphans after.
* feat(sdk): a3s-box-ci runner binary + warm_base infra-retry
- a3s-box-ci: a dep-free bin (in a3s-box-sdk) bridging any agent/tool to the
pipeline. `run [SPEC|-]` parses a line-based spec -> run_parallel -> JSON
Report (exit 0 iff passed); `sweep` reclaims crashed-pipeline orphans. This
is what lets a3s-code / Claude Code / Codex drive the pipeline from a script.
- warm_base now retries a transient infrastructure failure too (DRY'd with the
per-step fork via a shared retry_infra), so concurrent same-image warms stay
robust under load.
Validated end-to-end on real KVM (runner: real pipeline + sweep; a3s-code drives
it via session.program through the QuickJS runtime). 19 unit/bin tests + clippy.
* fix(runtime): rootfs-cache in-use guard prevents concurrent same-image corruption
RootfsCache::prune (called after a cache-miss put) evicted LRU entries with no
in-use guard, so it could remove_dir_all a cache entry that a CONCURRENT box was
using as its overlayfs lowerdir — that box's mount(2) then failed with ENOENT
('No such file or directory (os error 2)'), persisting through retries since the
backing was gone. Two pipelines from the same image collapse onto one cache key,
so this hit any concurrent same-image workload.
Fix: the same in-use guard SnapshotStore::prune already applies to live CoW
lowers. Each overlay box records the cache key it holds in <box_dir>/.rootfs-
cache-key (removed with the box dir); prune skips any still-referenced key
(prune_protecting, with prune as the empty-set wrapper).
Found via a concurrent-pipeline chaos test driven through a3s-code; verified on
a real /dev/kvm host (concurrency scenario: ~50% failure -> reliably green).
41 rootfs-cache unit tests + clippy clean.
* style(runtime): rustfmt the rootfs-cache in-use-guard test
---------
Co-authored-by: Roy Lin <roylin@a3s.box>
0 commit comments