Pausing and Resuming
OpenKruise Agents allows you to pause a running sandbox so that it stops consuming CPU / memory, and later
resume it back to a running state, keeping the sandbox identity (same sandboxID, same Pod) intact.
â ī¸ This area is still evolving. The underlying capture mechanism (whether memory state is preserved, whether the filesystem is checkpointed, etc.) depends on the cluster environment (e.g. memory-state preservation is currently only supported on Alibaba Cloud ACS). This document focuses on how to use the API; for state-preservation guarantees, see your platform runbook.
Overviewâ
Two parallel interfaces are provided, both acting on the same underlying Sandbox resource:
| Interface | Audience | Typical scenarios |
|---|---|---|
| E2B SDK (pause/connect) | Application code running on top of E2B Python / JavaScript | Programmatic pause before idle, resume on demand |
| Kubernetes CRD | Cluster ops, declarative GitOps, kubectl or custom control | Toggle spec.paused or schedule spec.pauseTime |
Pause/Resume is one-to-one: the sandbox ID stays the same across the pause â resume cycle. If you need a one-to-many "snapshot and fork" workflow, see Snapshot Management.
How It Works (summary)â
- Pause freezes the sandbox Pod. Active WebSocket / PTY / command-stream connections are dropped; clients must reconnect after resume.
- Resume brings the Pod back to the running state. The sandbox ID is preserved.
- The exact capture scope (memory / filesystem) depends on the runtime platform and the configuration on the
backing
SandboxSpec.
Pausing a Sandboxâ
- E2B SDK
- Kubernetes CRD
The E2B SDK exposes a pause() method on a sandbox handle. It calls the POST /sandboxes/{sandboxID}/pause
endpoint under the hood.
from e2b_code_interpreter import Sandbox
with Sandbox.create(template="code-interpreter", timeout=300) as sbx:
sbx.run_code("a = 1")
sbx.pause() # sandbox is now paused; sandboxID is retained
import { Sandbox } from 'e2b'
const sbx = await Sandbox.create({ template: 'code-interpreter', timeoutMs: 300_000 })
await sbx.betaPause()
Notes:
- Pausing a sandbox that is not in
runningstate returns409 Conflict. - The lifetime of a paused sandbox is controlled separately from its running timeout.
sandbox-manageruses theforeverpaused-retention policy by default; you can configure a shorter window as described in Retaining a Paused Sandbox.
Set spec.paused: true on the Sandbox CR. The controller drives the Pod into the paused state.
kubectl patch sbx my-sandbox -n default --type=merge -p '{"spec":{"paused":true}}'
You can also schedule an automatic pause via spec.pauseTime:
apiVersion: agents.kruise.io/v1alpha1
kind: Sandbox
metadata:
name: my-sandbox
namespace: default
spec:
pauseTime: "2026-05-13T10:00:00Z" # RFC3339; absolute time to auto-pause
Check the status phase:
kubectl get sbx my-sandbox -n default -o jsonpath='{.status.phase}'
# â Paused
Auto Pauseâ
In addition to calling pause explicitly, you can declare that the sandbox should auto-transition into paused
on expiry at creation time â when the timer fires the sandbox is not killed, it moves into the paused state with
its identity preserved, waiting for a later resume.
- E2B SDK
- Kubernetes CRD
Follow the E2B docs â Auto-pause: set
lifecycle.on_timeout to "pause" when creating the sandbox.
from e2b_code_interpreter import Sandbox
sbx = Sandbox.create(
template="demo",
timeout=600, # 10 minutes; on expiry go to paused instead of being killed
lifecycle={
"on_timeout": "pause",
"auto_resume": False, # see note below
},
)
import { Sandbox } from 'e2b'
const sandbox = await Sandbox.create({
template: 'demo',
timeoutMs: 10 * 60 * 1000, // 10 minutes; on expiry go to paused
lifecycle: {
onTimeout: 'pause',
autoResume: false, // see note below
},
})
â ī¸
auto_resumeis not yet implemented in OpenKruise Agents. Even if you set it totrue, a paused sandbox will not be woken up automatically; clients must still callSandbox.connect(sandbox_id, ...)explicitly when they need it (see the next section). Set it tofalseto make the semantics explicit.
Set spec.pauseTime on a SandboxClaim (or on the underlying Sandbox CR). When the absolute time is reached the
controller drives the sandbox into paused.
apiVersion: agents.kruise.io/v1alpha1
kind: SandboxClaim
metadata:
name: demo-sandbox-claim
namespace: default
spec:
templateName: demo
# RFC 3339 absolute time; the controller auto-pauses the sandbox on expiry.
# It is recommended to set this field programmatically, for example:
# sbc.Spec.PauseTime = metav1.NewTime(time.Now().Add(5 * time.Minute))
pauseTime: "2026-02-06T07:33:30Z"
The
SandboxCR itself also has aspec.pauseTimefield (see the previous section). The CRD path uses an absolute time rather than the "pause when the timeout expires" offset semantics of the E2B SDK â use the E2B SDK if you need the latter.
Retaining a Paused Sandboxâ
reserve-paused-sandbox-duration controls how long a timed Sandbox is retained after its pause transition is
applied. When the Sandbox pauses, OpenKruise Agents recalculates spec.shutdownTime as:
pause transition time + reserve-paused-sandbox-duration
The value must be a positive Go duration, such as 30m, 2h, or 168h.
The special value forever selects the built-in 100-year retention window; it does not create a truly infinite
deadline. Values such as 0, negative durations, and 1d are invalid (time.ParseDuration does not support a d
unit).
This policy only recalculates an existing timeout. A Sandbox created with the never-timeout extension has no
shutdownTime, so paused retention does not introduce one.
- E2B SDK
- Kubernetes CRD
Set the persisted retention policy at creation time with the
e2b.agents.kruise.io/reserve-paused-sandbox-duration metadata extension. It applies to auto-pause and to later
manual pauses:
from e2b_code_interpreter import Sandbox
sbx = Sandbox.create(
template="demo",
timeout=600,
lifecycle={"on_timeout": "pause", "auto_resume": False},
metadata={
"e2b.agents.kruise.io/reserve-paused-sandbox-duration": "2h",
},
)
To override the persisted value for a manual pause, pass the
x-e2b-kruise-reserve-paused-sandbox-duration request header. The accepted override is persisted for subsequent
pause operations when that request performs the running-to-paused transition:
sbx.pause(
headers={
"x-e2b-kruise-reserve-paused-sandbox-duration": "30m",
}
)
The resolution order is pause request header â persisted policy â forever default. If the creation metadata
or pause header contains an invalid value, sandbox-manager returns 400 Bad Request. Manager-created Sandboxes
without an explicit value use forever, which is persisted as the internal
agents.kruise.io/reserve-paused-sandbox-duration annotation.
For controller-driven auto-pause, add the agents.kruise.io/reserve-paused-sandbox-duration annotation and set both
spec.pauseTime and spec.shutdownTime. The annotation tells the controller to let the due pause run before
deletion and then replace shutdownTime with the pause transition time plus the retention window:
apiVersion: agents.kruise.io/v1alpha1
kind: Sandbox
metadata:
name: my-sandbox
namespace: default
annotations:
agents.kruise.io/reserve-paused-sandbox-duration: "2h"
spec:
pauseTime: "2026-05-13T10:00:00Z"
shutdownTime: "2026-05-13T10:00:00Z"
The direct CRD path intentionally has no default-when-absent policy: without the annotation, the controller does not
recalculate shutdownTime. If an explicitly present annotation is invalid, the controller logs the error and uses
the forever 100-year window for that auto-pause without rewriting the invalid annotation.
The annotation is evaluated when spec.pauseTime triggers auto-pause. It does not calculate a retention window
for a direct spec.paused: true patch; for a manual CRD pause, write the desired absolute spec.shutdownTime in the
same patch.
Resuming a Sandboxâ
The recommended interface on the E2B SDK side is Sandbox.connect(...) â it implicitly resumes a paused sandbox and
at the same time refreshes its timeout. The legacy resume endpoint still exists for backward compatibility but
should not be used by new code.
- E2B SDK
- Kubernetes CRD
from e2b_code_interpreter import Sandbox
sbx = Sandbox.connect(sandbox_id, timeout=300) # resumes if paused, and extends the timeout
sbx.run_code("print(a)")
import { Sandbox } from 'e2b'
const sbx = await Sandbox.connect(sandboxId, { timeoutMs: 300_000 })
Notes:
- If the sandbox is already running,
connectonly refreshes the timeout. The refresh is extend-only: the timeout will never be shortened. (Exception: a paused â running resume applies the requested timeout directly.) connecton a sandbox that does not exist or is owned by another API key returns404 Not Found.
Clear spec.paused (set it back to false). The controller will resume the Pod. You can also adjust
spec.pauseTime / spec.shutdownTime in the same patch to effectively "refresh the timeout while resuming":
kubectl patch sbx my-sandbox -n default --type=merge -p '{"spec":{"paused":false}}'
# Resume and also push the next auto-shutdown one hour out (example)
kubectl patch sbx my-sandbox -n default --type=merge \
-p '{"spec":{"paused":false,"shutdownTime":"2026-05-13T11:00:00Z"}}'
The CRD path has no extend-only guard. The E2B SDK's
connect + timeoutMsonly extends, never shortens, the remaining lifetime while running; the CRD path takes the user-written value verbatim and can shorten it. Pick the path that matches your intent.
Capability Matrixâ
| Capability | E2B SDK | Kubernetes CRD |
|---|---|---|
| Pause a running sandbox | â
sbx.beta_pause() | â
spec.paused: true |
| Resume a paused sandbox | â
Sandbox.connect(id, ...) | â
spec.paused: false |
| Auto-pause when the timeout expires | â
lifecycle.on_timeout='pause' | â |
| Auto-pause at a specific absolute time | â | â
spec.pauseTime |
| Auto-resume a paused sandbox | â not yet supported | â not yet supported |
| Configure deletion after entering paused | â creation metadata or pause header | â
annotation for auto-pause; write spec.shutdownTime for a manual pause |
| Set / refresh the sandbox timeout together with resume | â
Sandbox.connect(id, timeout=...) | â
write spec.shutdownTime / spec.pauseTime in the same patch |
| Extend-only guard on timeout refresh while running | â | â user-written value may shorten |
| Observe paused/running state | via SDK response | status.phase (Paused / Running) |
If you need "extend-only, never shorten" timeout semantics, use the E2B SDK. The CRD path is better suited for declarative / GitOps control over the paused/running bit plus absolute scheduling times.
Notesâ
- Connection drop. The Pod is frozen on pause; all active streams (WebSocket / PTY / command streams) disconnect. Clients must reconnect after resume.
- Timeout during pause. The running timeout does not continue counting down unchanged after pause. Auto-delete is
controlled by
spec.shutdownTime, which paused retention can recalculate from the pause transition time. - Old SDKs. The legacy
POST /sandboxes/{sandboxID}/resumeendpoint is kept for old SDK compatibility only. New code should always useSandbox.connect(...). - State-preservation caveats. Whether memory is preserved across pause/resume depends on the runtime platform. If you need explicit memory + filesystem snapshots that can also be cloned into brand-new sandboxes, use Snapshot Management instead.