Skip to content

Concepts

Checkpoints, snapshots and forks

Save a running desktop's full state, start new desktops from it, or fork it into N copies at once.

Checkpoints

Every desktop is restored from a checkpoint: a saved process tree (memory, open files, the X session, the apps) plus its file system. There are two kinds:

  • Base images, such as osworld-ubuntu, installed on the host by the operator and named by a template version. They are never deleted by leases.
  • Saved states, which you make from a running desktop. In the console they are Snapshots; in the SDK a State; in the HTTP API a checkpoint with a UUID id.

client.images() (GET /v1/checkpoints) lists both kinds that your workspace can launch on its host.

Save a state

env.save() (HTTP capture) saves the desktop's current state; the desktop keeps running. Start new desktops from it with client.create(from_state=state):

Python
import drums

with drums.connect() as client:
    with client.create(task="e0df059f", ttl=900) as env:
        env.wait_valid()
        env.step("pyautogui.click(960, 540)")
        state = env.save(name="after-first-click")      # a snapshot in the console
        print("saved", state)
        with client.create(from_state=state, ttl=600) as copy:
            copy.wait_valid()
            print("restored", copy.id, copy.from_state == state)
    client.delete_state(state)                          # frees ~0.6 GB of host memory

Saving is safe right after an action: the runtime first waits until the process tree is quiet (no process or thread starting or exiting for 1 s, at most 30 s by default) and checks that what it dumped is that tree. If the tree never becomes quiet, NotQuiescent is raised and nothing is captured.

Fork

env.fork(n) (HTTP branch) saves the desktop's state and starts n new desktops from it concurrently. Each child is an independent computer with its own id and a new episode with its own gate report; the parent keeps running.

Python
import drums

with drums.connect() as client:
    with client.create(task="e0df059f", ttl=900) as env:
        env.wait_valid()
        # closes the children when the block ends
        with env.fork(2, keep_state=False) as kids:
            print("fork state", kids.state, "children", [k.id for k in kids])
            for k in kids:
                k.wait_valid()  # raises GateFailed if the child's episode is invalid
                print(k.id, k.episode, k.gates()["validity"]["verdict"])
  • keep_state=False deletes the fork's saved state when its last child closes. Use it in loops: otherwise each fork keeps one saved state until you delete it or its lease runs out.
  • strict=True (the default) raises ForkError if any child did not come up; ForkError.ok holds the children that did.
  • Children count against your workspace's live-computer limit, and n is limited by the host (max_fork_n, 8 on the current pilot host). See Limits.
  • A child inherits the parent's set-up task state; the task's setup is not run again.

Where saved states live

Important

Saved states live in the worker host's memory (a RAM-backed state directory). They are lost if the host reboots, restore only on the host that captured them, and cannot be downloaded. Each one holds about 0.6 GB of host memory, and the host holds a limited number (5 on the current pilot host).

LeaseDefaultChange it with
Idle timeout: deleted after this long with no desktop made from it1800 ssave(idle_timeout=), fork(state_idle_timeout=)
Time to live once no desktop uses itnonesave(ttl=), fork(state_ttl=)

A saved state cannot be deleted while a desktop made from it exists (Conflict, HTTP 409). Base images cannot be deleted through the API.

In the console

Snapshots lists saved states with their lineage: the parent snapshot, the computer it was captured from, and the computers made from it. A ready snapshot can be restored into one new computer, forked, or deleted (by its creator, admins and owners). Snapshot states are Capturing, Ready, Failed, Deleting and Deleted.