Auto-suspend and AutoResume

Coppice now accepts the E2B lifecycle shape on create: timeoutMs plus lifecycle: { onTimeout: “pause”, autoResume: true }. The reaper pauses idle jail-backed sandboxes and bhyve SSH guests instead of killing them, and envd/files/commands activity resumes a paused sandbox before dispatching work.

Wire shape

Create payload:

{
  "templateID": "python",
  "timeoutMs": 600000,
  "lifecycle": {
    "onTimeout": "pause",
    "autoResume": true
  }
}

Accepted aliases:

autoResume=true is valid only with onTimeout="pause". The default stays kill-on-timeout, preserving existing TTL behavior for callers that do not opt into persistence.

What counts as activity

The shared activity hook lives in e2b-compat/src/state.rs::touch_sandbox_activity. It is called from:

When a matching sandbox is paused and has autoResume=true, the hook calls the owning backend’s resume, marks the sandbox running, bumps coppice_sandboxes_resumed_total, refreshes lastActiveAt, and starts a new timeout window.

The timeout window after auto-resume follows E2B’s compatibility rule: at least five minutes after wake-up, or the original timeout if it was longer. Normal running activity refreshes the caller’s original timeout.

Reaper behavior

e2b-compat/src/reaper.rs now decides per sandbox:

Jail pause/resume is implemented with SIGSTOP/SIGCONT over jail processes. Pool-backed bhyve SSH guests and host-console guests now use the same signal model through coppice-bhyve-pool-ctl.sh pause/resume or console-pause/console-resume. A paused bhyve pool entry stays owned by the sandbox and counts as coppice_bhyve_pool_in_use, so the warm-pool reconciler will not hand it to another caller.

Receipt

The smoke rig is:

mise run lifecycle:auto-suspend-resume-honor

It creates a fresh python jail, waits for idle pause, sends an envd /execute request with Host: 49999-<sandbox-id>.coppice.lan, and asserts:

Receipt files land in benchmarks/results/auto-suspend-resume/.

The bhyve-specific gateway smoke is:

mise run lifecycle:bhyve-pause-resume-honor

It creates a fresh python-bhyve sandbox, proves /exec, pauses via POST /sandboxes/:id/pause, checks state="paused" and pause metrics, resumes via POST /sandboxes/:id/resume, then proves /exec still works. Receipts land in benchmarks/results/bhyve-pause-resume/.

Cross-refs