Automatic Pause and Resume
When AI agent workloads run at scale, idle sandboxes still occupy CPU and memory. OpenKruise Agents can pause a sandbox automatically after it reports idle for a sustained period, and wake it up before the next scheduled task or when inbound traffic arrives, improving cluster resource utilization and reducing the cost of idle compute.
Automatic pause/resume is configured on the SandboxSet through runtime probes and lifecycle policies. This document
also covers pause strategies, which control what is preserved when a sandbox pauses. For pausing and waking an
individual sandbox on demand â the E2B SDK pause() / connect() methods, the Sandbox CR spec.paused field, and
timeout-based auto-pause â see Pausing and Resuming.
Prerequisitesâ
- A
SandboxSethas been created and its sandboxes have been claimed by agents. See Warm Pool Management and Sandbox Claim. - Probe-driven automatic pause and scheduled wake-up require the
AutoPauseControllerfeature gate to be enabled onsandbox-controller. - Inbound-traffic wake-up only takes effect for requests routed to the sandbox through the
Sandbox Gateway, and the gateway must be configured with
enable-wake-on-trafficenabled.
Pause Strategiesâ
spec.pauseStrategy is an optional field of SandboxSet.spec. It specifies how a sandbox is paused when
spec.paused is set to true. When it is not configured, the default strategy is used, which is identical to the
existing behavior â existing configurations require no change.
| Strategy | Configuration | What is preserved |
|---|---|---|
| Default | Omit spec.pauseStrategy | Before pausing, the sandbox filesystem (rootfs) is persisted to the volume backing the sandbox. |
| Stop | pauseStrategy.type: Stop | Nothing is saved. Only PVC data is retained; the rootfs filesystem is lost. |
| Snapshot | pauseStrategy.type: Hibernate with hibernateStrategy.type: Snapshot | Before pausing, the sandbox filesystem (rootfs) is persisted to a snapshot. |
Configure the Stop strategy:
apiVersion: agents.kruise.io/v1alpha1
kind: SandboxSet
metadata:
name: code-interpreter
namespace: default
spec:
replicas: 4
pauseStrategy:
type: Stop
template:
spec:
containers:
- name: sandbox
image: <YOUR_IMAGE>
resources:
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: "1"
memory: 1Gi
Configure the Snapshot strategy:
apiVersion: agents.kruise.io/v1alpha1
kind: SandboxSet
metadata:
name: code-interpreter
namespace: default
spec:
replicas: 4
pauseStrategy:
type: Hibernate
hibernateStrategy:
type: Snapshot
persistentContents: # only `filesystem` (rootfs) is currently supported
- filesystem
template:
spec:
containers:
- name: sandbox
image: <YOUR_IMAGE>
resources:
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: "1"
memory: 1Gi
probes, autoPausePolicy, pauseStrategy, and persistentContents are all top-level fields of SandboxSet.spec.
Only container, resource, and scheduling fields belong in spec.template.spec.
Pausing a sandbox releases its compute resources to reduce cost. Trigger a pause only when there are no active requests or long-lived connections; see Caveats.
How Probes and Policies Workâ
spec.probes is a top-level field of SandboxSet.spec that defines probes executed periodically while the sandbox
runs. A probe only runs a command and reports the result â it does not itself decide whether the sandbox pauses or
wakes up. spec.autoPausePolicy references probe results by name and interprets their standard output:
- Pause rules use
messageRegexto match probe output and detect whether the agent is idle. - Resume rules use
timeFormatto parse probe output as the time of the next task.
spec.probes works independently of autoPausePolicy: probes run even without any policy configured, and their
results can be inspected through Sandbox conditions. Once a policy is configured, it reads the condition of the
referenced probe by name. The same probe can be referenced by one or more policies, but idle detection and scheduled
wake-up usually require different output formats â define separate probes for them, such as the Active and Cron
probes in the examples below.
Only exec probes are currently supported.
| Field | Required | Description |
|---|---|---|
name | Yes | Name of the probe. Must be unique within the same SandboxSet and must exactly match the probe field of autoPausePolicy. The probe result is reported in the Sandbox condition of type agents.kruise.io/<name>. |
containerName | No | Container in which the probe runs. Defaults to the first container in the Pod. |
exec.command | Yes | Command and arguments executed in the target container. The command is not run through a shell; for pipes, redirections, or conditionals, invoke the shell explicitly with sh -c as in the examples. |
periodSeconds | No | Interval between probe executions, in seconds. 30 means the probe runs every 30 seconds. Setting it explicitly is recommended. |
timeoutSeconds | No | Timeout of a single probe execution, in seconds. 5 means the command is considered failed once it runs longer than 5 seconds. Setting it explicitly is recommended. |
When a probe command exits with code 0, the condition status is True and the standard output is recorded in the
condition message. Output of failed or timed-out probes is never used to trigger automatic pause or wake-up.
Express both business state and task times through standard output only, and keep debug logs out of it.
Auto Pause When Idleâ
The following SandboxSet checks whether the agent is active every 30 seconds. A claimed sandbox is paused
automatically after the Active probe reports idle for 10 consecutive minutes.
apiVersion: agents.kruise.io/v1alpha1
kind: SandboxSet
metadata:
name: agent-sandbox-pool
namespace: default
spec:
replicas: 4
probes:
- name: Active
containerName: sandbox
periodSeconds: 30
timeoutSeconds: 5
exec:
command:
- sh
- -c
- |
# Example only; define the idle state according to your business.
if openclaw sessions list --active 900 2>/dev/null | grep -q .; then
echo "active"
else
echo "inactive"
fi
autoPausePolicy:
pause:
whenProbedIdleState:
probe: Active
messageRegex: "^inactive$"
thresholdDuration: 10m
template:
spec:
containers:
- name: sandbox
image: <YOUR_IMAGE>
- The
Activeprobe runs the idle-detection command in thesandboxcontainer every 30 seconds. Its name matches the value ofautoPausePolicy.pause.whenProbedIdleState.probe. - The example command lists sessions active within the last 900 seconds (15 minutes);
grep -q .checks for non-empty output â the probe printsactiveif any session is active andinactiveotherwise.2>/dev/nullkeeps error messages out of the probe's standard output. Adjust the900window to match how your business defines idle. - A probe should exit with code
0and print onlyactiveorinactiveto standard output. The conditionstatustells whether the probe ran successfully; the business state is carried bymessage. pause.whenProbedIdleState.probereferences theActiveprobe defined inspec.probes, andmessageRegex: "^inactive$"matches its idle output.thresholdDurationis required and cannot be negative. With10m, the timer starts when the probe first reportsinactive, and the sandbox pauses after 10 consecutive minutes ofinactive. With0, the sandbox pauses as soon as the probe reportsinactiveonce. In this example the activity window is 15 minutes and the threshold is 10 minutes, so it typically takes about 25 minutes from the last session activity to the pause.
When the idle probe times out, fails, or the configuration is invalid, the system keeps the sandbox running as the
conservative fallback. Warm sandboxes managed by the SandboxSet but not yet claimed still run probes, but they do
not participate in automatic pause decisions; the policy takes effect once a sandbox is claimed.
The following status shows a sandbox that is still running while waiting for the idle threshold to elapse. After the
Active probe first reports inactive, the controller computes the expected pause time from the condition's
lastTransitionTime plus thresholdDuration and writes it into nextPauseTime. For example, with the probe
reporting idle continuously from 2026-09-09T10:00:00Z and a thresholdDuration of 10 minutes:
apiVersion: agents.kruise.io/v1alpha1
kind: Sandbox
status:
phase: Running
conditions:
- type: agents.kruise.io/Active
status: "True"
reason: Succeeded
message: inactive
lastTransitionTime: "2026-09-09T10:00:00Z"
schedules:
- reason: probedIdle
nextPauseTime: "2026-09-09T10:10:00Z"
- The condition
typeis the fixed prefixagents.kruise.io/plus the probe nameActive; renaming the probe changes the condition type accordingly. status: "True"means the probe executed successfully; the business state is inmessage: inactive.nextPauseTimeis the predicted pause time and does not mean the pause has been triggered. If the probe reportsactivebefore that time, the controller clearsnextPauseTimeand the sandbox keeps running; if the probe keeps reportinginactiveuntil then, the controller pauses the sandbox and clearsnextPauseTime.
Auto Wake Before Scheduled Tasksâ
The following SandboxSet obtains the time of the next scheduled task as a Unix timestamp in seconds every 30
seconds, and wakes a paused sandbox 5 minutes before the task.
apiVersion: agents.kruise.io/v1alpha1
kind: SandboxSet
metadata:
name: agent-sandbox-pool
namespace: default
spec:
replicas: 4
probes:
- name: Cron
containerName: sandbox
periodSeconds: 30
timeoutSeconds: 5
exec:
command:
- sh
- -c
- |
# Example only; obtain the next task time according to your business.
NEXT_MS=$(openclaw cron list --json 2>/dev/null \
| jq -r '[.[] | select(.enabled != false) | .nextRunAtMs] | map(select(. != null)) | sort | .[0]')
if [ -n "$NEXT_MS" ] && [ "$NEXT_MS" != "null" ]; then
echo $((NEXT_MS / 1000))
else
echo "none"
fi
autoPausePolicy:
resume:
whenProbedScheduleTime:
probe: Cron
timeFormat: unix
leadTime: 5m
template:
spec:
containers:
- name: sandbox
image: <YOUR_IMAGE>
- The
Cronprobe obtains the next task time in thesandboxcontainer every 30 seconds. Its name matches the value ofautoPausePolicy.resume.whenProbedScheduleTime.probe. - The example command lists scheduled tasks, filters enabled tasks that have a
nextRunAtMsvalue, sorts them by time, and takes the earliest.nextRunAtMsis a Unix timestamp in milliseconds, so it must be divided by 1000 before being printed. - A probe should exit with code
0and print exactly one value to standard output. WithtimeFormat: unix, the value must be a Unix timestamp in seconds as a positive integer, such as1788516000. The controller trims leading and trailing whitespace and newlines, but cannot parse millisecond timestamps, values with units, date strings, JSON, or interleaved log output. - When there is no next task, the script prints
none. This tells the controller that no task time is available, and no wake-up schedule is created. resume.whenProbedScheduleTime.probereferences theCronprobe defined inspec.probes.timeFormatspecifies how the probe output is parsed.unix(also the default) parses a Unix timestamp in seconds;datetimeparses an RFC3339 time that carries a timezone.leadTimespecifies how far ahead of the task the sandbox wakes up. The default is5m;0wakes the sandbox exactly at the task time; negative values are invalid.
This example only configures automatic wake-up: the sandbox must first be paused manually, via spec.pauseTime, or
through other pause rules. To combine idle auto-pause with scheduled wake-up, merge the pause and resume
configurations of the two examples.
When the wake-up probe is unavailable or fails, no wake-up schedule is created; if automatic pause rules are configured at the same time, automatic pause is not triggered either. When the probe succeeds but its output cannot be parsed, no wake-up schedule is created, while the idle rules can still pause the sandbox.
The following status shows the sandbox after the Cron probe reports the next task time. 1788516000 is
2026-09-04T10:00:00Z; with a leadTime of 5 minutes, the controller writes the predicted wake-up time into
nextResumeTime:
apiVersion: agents.kruise.io/v1alpha1
kind: Sandbox
status:
phase: Running
conditions:
- type: agents.kruise.io/Cron
status: "True"
reason: Succeeded
message: "1788516000"
lastTransitionTime: "2026-09-04T09:50:00Z"
schedules:
- reason: probedSchedule
nextResumeTime: "2026-09-04T09:55:00Z"
- The condition
typeis the fixed prefixagents.kruise.io/plus the probe nameCron. status: "True"means the probe executed successfully;messageis its standard output.nextResumeTimeis the predicted wake-up time computed from the task time andleadTime. Once the sandbox pauses, the controller uses the recordednextResumeTimeto trigger the wake-up. If the probe later reports a new task time, the value is recomputed; if the output isnoneor otherwise unparseable, the value is cleared.
Time and Timezone Requirements for Scheduled Wake-upâ
The wake-up time is computed as the probed next task time minus leadTime. leadTime is a plain duration â the
default is 5 minutes, it can be set to 0, but it cannot be negative.
timeFormat: unixâ the probe must print a Unix timestamp in seconds as a positive integer, such as1788516000. A Unix timestamp denotes one absolute instant since1970-01-01T00:00:00Zand carries no timezone, so the wake-up moment is not affected by the timezone or region the controller runs in.timeFormat: datetimeâ the probe must print an RFC3339 time with a timezone, such as2026-09-04T18:00:00+08:00or2026-09-04T10:00:00Z(both denote the same instant). A value like2026-09-04 18:00:00â no timezone and not RFC3339 â cannot be parsed.
The main timezone risk is converting local business time into a Unix timestamp inside the probe. For example, when
converting the local time 2026-09-04 18:00:00 in UTC+8, the conversion must explicitly use the +08:00 offset or
the Asia/Shanghai timezone; parsing it as UTC introduces an 8-hour offset. A correctly generated Unix timestamp is
no longer affected by the controller's timezone.
Also double-check the timestamp unit: JavaScript's Date.now() and nextRunAtMs in the example return milliseconds
and must be divided by 1000 before being printed. The controller neither recognizes nor converts millisecond
timestamps automatically.
Using unix and printing a seconds-level positive integer directly from the probe is recommended. If the next task
happens at 2026-09-04T18:00:00+08:00, whose Unix timestamp is 1788516000, the sandbox is woken at
2026-09-04T17:55:00+08:00 on the same absolute timeline with a leadTime of 5 minutes.
How autoPausePolicy, pauseTime and E2B timeout Relateâ
spec.autoPausePolicyis an always-on, probe-driven policy: it can pause the sandbox based on idle state and wake it based on the next task time.Sandbox.spec.pauseTimeis a one-shot absolute pause time in RFC3339 format. When the time is reached, the controller setsspec.pausedtotrue.- The two can be configured together and take effect independently â whichever condition is satisfied first triggers
the pause. An expired
pauseTimeis not cancelled even if the probes report the agent as active. - When creating a sandbox with the E2B SDK, the client only passes a relative
timeoutin seconds. Withlifecycle.on_timeoutset topause,sandbox-managerconverts it intospec.pauseTimeas the server's current time plus timeout; the E2B client never reads or setspauseTimedirectly. - If pausing should be fully decided by probe policies, do not set
spec.pauseTimeon theSandboxCR. When creating or claiming a sandbox through the E2B SDK, set the"e2b.agents.kruise.io/never-timeout": "true"metadata extension so that nopauseTimeorshutdownTimeis generated â this does not preventautoPausePolicyfrom togglingspec.paused.
Auto Wake on Inbound Trafficâ
A paused sandbox can also be woken up automatically by inbound requests. This capability only applies to agent traffic routed through the Sandbox Gateway.
- E2B SDK
- SandboxSet CRD
Set lifecycle.on_timeout to pause and lifecycle.auto_resume to True when creating the sandbox:
from e2b_code_interpreter import Sandbox
sandbox = Sandbox.create(
template="code-interpreter",
timeout=600,
lifecycle={
"on_timeout": "pause",
"auto_resume": True,
},
)
# Get the sandbox hostname for a given port
host = sandbox.get_host(3000)
print(f"https://{host}")
The sandbox pauses automatically after the timeout. While it is paused, sending a request to its hostname wakes it
up â no Sandbox.connect() call is needed first. After the wake-up, the auto-pause countdown restarts from the
wake-up moment using the timeout set at creation; positive values smaller than 5 minutes are treated as 5 minutes.
auto_resume currently only wakes the sandbox on inbound traffic addressed to the sandbox hostname. SDK operations
such as sandbox.commands or sandbox.files do not trigger the wake-up; call Sandbox.connect(...) first for
those.
Configure spec.autoPausePolicy.resume.onIngressTraffic:
apiVersion: agents.kruise.io/v1alpha1
kind: SandboxSet
spec:
autoPausePolicy:
resume:
onIngressTraffic:
pauseTimeout: 5m
pauseTimeout re-arms the timeout-based auto-pause countdown after a traffic wake-up. It only applies to sandboxes
with spec.pauseTime configured; if it is unset or not greater than 0, the countdown is not reset. Positive values
smaller than 5 minutes are treated as 5 minutes.
For how clients resolve sandbox hostnames and domains, see E2B Client. For configuring traffic
wake-up on an individual Sandbox CR, and for how concurrent requests share one resume operation, see
Pausing and Resuming.
Verify Automatic Pause and Resumeâ
Inspect probe results and the next scheduled pause/wake-up times. Replace <RESOURCE_NAME> and <NAMESPACE> with
your values:
kubectl get sandbox <RESOURCE_NAME> -n <NAMESPACE> -o jsonpath='{.status.conditions}'
kubectl get sandbox <RESOURCE_NAME> -n <NAMESPACE> -o jsonpath='{.status.schedules}'
When a probe runs successfully, the corresponding condition has status True and its message holds the probe's
standard output. While idle matching is in progress, status.schedules shows nextPauseTime; when a valid scheduled
task exists, it shows nextResumeTime.
Observe Paused Sandboxesâ
Pods of paused sandboxes do not consume cluster CPU or memory. Check the sandbox phase with:
kubectl get sandbox <RESOURCE_NAME> -n <NAMESPACE> -o jsonpath='{.status.phase}'
# â Paused
To observe the resource usage of sandbox pods, use your monitoring stack, for example a Prometheus-based dashboard.
Delete a Paused Sandboxâ
To remove a paused sandbox completely, delete the Sandbox resource.
- E2B SDK
- Kubernetes CRD
Replace <YOUR_SANDBOX_ID> with the actual sandbox ID:
from e2b_code_interpreter import Sandbox
sandbox = Sandbox.connect("<YOUR_SANDBOX_ID>")
sandbox.kill()
kubectl -n <NAMESPACE> delete sandbox <RESOURCE_NAME>
Caveatsâ
- Wake-up may fail. Pausing reclaims the sandbox's compute resources (CPU and memory); waking it up may fail if the cluster cannot schedule the required resources at that moment. Retry later, or adjust the resource requirements.
- Request interruption and lost long connections. Pausing freezes the sandbox CPU immediately â in-flight requests fail. Long connections (WebSocket, SSE, gRPC) are not restored after wake-up; clients must reconnect. Trigger a pause only after confirming there are no active requests or long connections.
- Data loss with the Stop strategy. With
pauseStrategy.type: Stop, neither therootfsnor the in-memory state is preserved; data not written to a PVC before pausing is lost after wake-up. To preserve the container filesystem across pause, use the default or the Snapshot strategy (see Pause Strategies).
Further Readingâ
- Pausing and Resuming â manual pause/wake-up, timeout-based auto-pause, and paused-sandbox retention.
- Warm Pool Management â creating and managing sandboxes with
SandboxSet. - Snapshot Management â checkpoint and fork workflows for sandboxes.
- E2B Client â connecting the E2B SDK to
sandbox-manager.