Skip to main content
Four clocks can stop work in a sandbox, but only two end the sandbox itself. Which clock ran out tells you whether your work stopped and whether the sandbox is still there.
A sandbox is created, runs for a finite lifetime and is destroyed by default. A command timeout ends the command; a client timeout ends only the wait. Neither ends the sandbox.A sandbox is created, runs for a finite lifetime and is destroyed by default. A command timeout ends the command; a client timeout ends only the wait. Neither ends the sandbox.A sandbox is created, runs for a finite lifetime and is destroyed by default. A command timeout ends the command; a client timeout ends only the wait. Neither ends the sandbox.A sandbox is created, runs for a finite lifetime and is destroyed by default. A command timeout ends the command; a client timeout ends only the wait. Neither ends the sandbox.

With the default ending, BoxRouter destroys the sandbox at or after the end of its lifetime; the exact timing is not guaranteed. Files a later sandbox needs belong in a Volume. The lifetime starts as sandbox creation begins on the selected route. A command or client timeout never ends the sandbox.

States

state says which stage of its lifecycle a sandbox is in. Fetching one sandbox asks for a current observation, and a list shows the last state BoxRouter recorded. After a sandbox ends, its record can remain available even when a live observation is unavailable. In a detail response, observed_at is when BoxRouter read the state and state_recorded_at is when the state was last recorded. state_recorded_at can be null when no timestamp is available or a lifecycle change overtook the read. Fetch again before relying on that state. Cost shows what each provider charges while paused. state_reason says what put the sandbox in its state: requested (a call you made), lifetime, idle_shutdown, retention (a paused sandbox passed kept_until) or external (a change made at the provider). state can also have these values:
  • error: the provider reported a failure. Read failure before acting.
  • unknown: BoxRouter could not map the provider’s state. native_state contains the state as the provider reported it.
New values can be added. Handle unfamiliar states instead of failing.

The Four Clocks

Create a sandbox and Run a command give each field’s default and limits.

Command Deadline

At the deadline, the command’s process group receives TERM and then KILL. The call still succeeds: the result has timed_out set to true, no exit_code, and the output the command wrote before it was ended. A 504 timeout with outcome: unknown is left for a command whose answer BoxRouter lost. Its operation reads completed with settled_by: wait_timeout, which means BoxRouter stopped waiting, not that the command ended. A child started with setsid leaves the process group and keeps running after the deadline. While it holds the command’s output open, the call returns only when that child exits. Start long work as a process instead.

Client Wait

A client that gives up early cancels nothing. The command keeps running until it exits or reaches its own deadline, and its operation is still recorded. Read the operation before you send the command again, and make the client wait longer than timeout_seconds.

Inactivity

Set requirements.idle_shutdown at creation to pause or destroy a sandbox nobody is using. A route that doesn’t provide idle shutdown is not eligible. When idle shutdown pauses a sandbox, its state is paused, the same as after you pause it yourself. Each route decides which activity resets its idle timer, and a running command doesn’t always count. Set idle_seconds longer than your longest silent command, or don’t use idle shutdown for that sandbox.

Lifetime

The lifetime starts when BoxRouter begins creating the sandbox on the selected route. Time spent creating it counts, so less time may remain when the sandbox is ready. Each surface has one default when you set no lifetime: The default for create is the one the request lifetime_seconds falls back to. A route’s longest run is lifetime.max_seconds. With credits on a route that can extend a lifetime, you can leave out lifetime_seconds and run while funded. lifetime.ends_at is when the lifetime runs out. BoxRouter sets the provider’s own timer for it, and the provider ends the sandbox when that timer fires. Only routes whose timer gives your at_end are eligible. BoxRouter states no exact end time, so the sandbox can run past ends_at. Paused time doesn’t count against the lifetime. While a sandbox is paused, watch kept_until: BoxRouter destroys the sandbox then unless you resume it. A paused sandbox has no ends_at. Check remaining_seconds before resuming to see the lifetime budget left. Each route has a longest single run, lifetime.max_seconds. A request for a longer lifetime rules that route out. To run longer than you first asked, set resources.extendable_lifetime when you create the sandbox, then extend the lifetime while it runs. A command can finish successfully after lifetime.ends_at if the sandbox is still running. If the sandbox ends during the command, the call can fail with 410 sandbox_ended and an unknown outcome. Check what it changed before you run it again in a new sandbox. Once the sandbox has ended, any call other than get, list, and destroy answers 410 sandbox_ended; details names what ended it and when. The record still reads for its retention, and destroy stays a safe resend.

Next Steps

Pause, Resume, and Extend

Pause, resume, extend and idle shutdown, step by step.

Recover from Errors

What to do after a timeout or an unknown outcome.

Check Your Limits

The lifetime and other limits your route sets.