Sailboxes preserve their writable disk, in-memory state, and in-flight network
requests across checkpoints and resumes.
Any Sailbox you resume can come back cold instead, with the disk intact and
nothing running, and one that has an upgrade waiting always does. Write code
that expects a cold start.
The examples below assume a running Sailbox sb.
Sail may also sleep a Sailbox on its own, but only when nothing would notice:
no CPU or network activity, no process waiting on a timer, and no open
connections a sleep would break. A slept Sailbox wakes transparently on
traffic or the next operation.
Waking takes a couple of seconds. That is free for a batch job and unwelcome if
someone is waiting at a terminal, so you can turn automatic sleep off for a
Sailbox, or choose how long it must be idle before Sail may sleep it.
A numeric setting replaces Sail’s default idle wait, so it can make automatic
sleep happen sooner or later. The idle window only controls when Sail may
consider sleeping the Sailbox. Sail still waits until the Sailbox is fully idle,
and its periodic check can make the actual sleep happen later. Choose a whole
number of seconds from 1 through 3600. A value of 0 restores Sail’s default.
Other numeric values are rejected. Your own sleep(), pause(), resume(),
and scheduled wakes work the same either way.
Checkpoint
checkpoint() creates a durable checkpoint handle. Running Sailboxes are
snapshotted first. Paused and sleeping Sailboxes return a handle to their
existing checkpoint without waking.
Call checkpoint() after important setup, such as installing packages,
fetching remote data, or writing files. On host failure, Sail restores from the
most recent completed checkpoint and does not replay commands that ran before
that checkpoint.
name labels the handle. A checkpoint lasts seven days unless you set a TTL.
Set one when you keep a checkpoint to reuse as a template, so the handle does
not expire while you still need it. The returned handle carries the expiry time
(expires_at), after which starting a Sailbox from it fails.
Start From Checkpoint
Create a separate running Sailbox from a durable checkpoint handle:
The child restores the memory saved in the checkpoint as well as the writable
disk, so processes the original was running carry on in the child. Commands you
started with exec stop in the child, though their writes up to the checkpoint
are kept, and one you started with the background option keeps running there.
Start the other commands the child needs again.
Sometimes the child comes up cold instead, with the disk intact and nothing
running. Write code that expects a cold start.
The child gets new Sail identity and networking. Active TCP connections are
reset in the child. A child starts with no inherited ingress, so add the ports
the child should publish with
expose.
checkpoint() does not support a Sailbox that has volume mounts. Create a
separate Sailbox without volume mounts before you create a checkpoint handle.
Upgrade a Sailbox that uses an older guest payload before checkpointing it.
Sleeping and paused Sailboxes can be cloned too: checkpoint() returns the
existing checkpoint handle without waking the parent. Starting multiple
children from the same checkpoint reuses the same checkpoint artifacts, so the
second and later children avoid re-checkpointing the parent.
Fan Out to Many Sailboxes
Starting many children from one checkpoint is the fast path to a fleet of
identical environments, for example agent rollouts, parallel test shards, or
grading many submissions at once. Prepare one Sailbox (install dependencies,
warm caches, start servers), checkpoint it, then start every worker from that
checkpoint instead of repeating the setup in each one:
Use the concurrent forms shown here (.aio twins in Python, promises in
TypeScript, joined futures in Rust) so the restores overlap instead of running
one at a time, and collect the results per child, as the examples do, so one
failed restore does not cost you the children that did come up. Give each
child a distinct name, and pass a timeout so a stuck restore fails that
child instead of stalling the whole batch.
Each child is a full, separate Sailbox: it bills like one and keeps running
until it sleeps or you terminate it, so clean up the fleet when the work is
done. If one process drives hundreds of Sailboxes concurrently, you can also
give the SDK’s thread pool more headroom; see
Configuration.
Pause
pause() checkpoints the Sailbox and powers it down until you explicitly resume
it:
Use pause when you want to preserve state but do not want the Sailbox to wake on
network traffic.
Sleep
sleep() checkpoints the Sailbox and powers it down until network ingress,
exec, or an explicit resume wakes it:
Use sleep for idle services that should wake when they receive traffic.
Resume
resume() restores a paused or sleeping Sailbox:
exec and file operations wake a sleeping Sailbox automatically, so binding
an existing Sailbox by id needs no explicit resume in any language.
Sleep Until a Wake
Pass a wake time to sleep() to schedule a wall-clock wake as the Sailbox
goes down. When the moment arrives and the Sailbox is still sleeping, Sail
restores it:
Each Sailbox holds one scheduled wake. A request earlier than the current
scheduled wake replaces it. A later request leaves the sooner wake in place.
The call returns the effective wake time (the sooner of the two). Schedule
the next wake after the current one fires if you need a series.
Calling sleep with a wake time on a Sailbox that is already sleeping just
updates the scheduled wake. The CLI accepts a delay like 30m or 2h, or
an absolute RFC 3339 timestamp. The wake can fire a little after the time
you set, so treat it as approximate. Schedule a minute or two of headroom
rather than an exact deadline. Paused Sailboxes only wake on an explicit
resume and reject scheduled wakes.
Use scheduled wakes for agents and services that sleep between runs and need
to be running again at a known time, such as a daily job or a follow-up an
agent set for itself.
Upgrade
upgrade() reboots the Sailbox on its same disk onto the latest in-guest Sail
agent, picking up new features, fixes, and performance improvements without
recreating the Sailbox:
The filesystem is fully preserved; running processes stop and the Sailbox boots
fresh, like a machine reboot. Restart any long-running services afterwards.
On a running Sailbox the upgrade applies immediately and applied is true. On
a paused or sleeping Sailbox the upgrade is recorded without waking it and
applied is false; it applies automatically the next time the Sailbox wakes. A
Sailbox that is already on the current runtime version reports true without
rebooting.
A Sailbox whose runtime is too old for Sail to resume safely is
upgraded automatically the next time it wakes, as if upgrade() had been
called on it first.
Before a runtime version reaches that automatic-upgrade cutoff, get and
list return a deprecation notice with a deadline and upgrade instructions.
The CLI and Python/TypeScript SDKs also surface the first such notice as a
warning once per process (Python emits SailDeprecationWarning through the
warnings module); Rust callers
can install a callback with sail::set_notice_handler. Treat it as advance
notice to schedule upgrade() on your own terms before the deadline; it is not
an immediate failure.
Terminate
terminate() permanently destroys the Sailbox:
Termination is not reversible. Use pause() or sleep() when you want to keep
the VM state for later.