Descanto Docs
CantoConcepts

Desktops and lifecycle

Lifecycle states and generation fencing.

A desktop is a real, persistent Linux machine: an id, an org, a tier, an image version, and a disk that survives hibernation. Its wire shape (DesktopJson) is what every desktop-returning route responds with:

{
  "id": "...",
  "org_id": "...",
  "tier": "small",
  "state": "awake",
  "image_version": "...",
  "generation": 3,
  "current_generation_id": "...",
  "idle_timeout_secs": 900,
  "billing_mode": "hourly",
  "host_id": "..."
}

Lifecycle states

A desktop's state field is one of:

StateMeaning
provisioningJust created, not yet placed on a host.
wakingA wake operation is in flight.
awakeRunning -- compute is billed, guest ops (exec/files/stream) are available.
hibernatingA hibernate operation is in flight.
hibernatedStopped -- disk state preserved, compute not billed.
destroyedPermanently gone, along with its disk. Irreversible.

wake, hibernate, and destroy are the three mutating transitions, triggered by POST /v1/desktops/{id}/{wake,hibernate,destroy}. Each of those returns an operation handle rather than blocking until the transition finishes -- see that page for the polling model.

Guest operations (exec, files, stream) only work while a desktop is awake; calling them against a desktop in any other state is a 409 Conflict (see API overview).

Generation fencing

Every desktop carries a generation, an integer that increments across its lifecycle transitions. Mutation requests can optionally include an expected_generation in the request body:

{ "expected_generation": 3 }

If the desktop's current generation doesn't match, the operation settles failed with a "generation mismatch" error, surfaced as 409 Conflict when observed through ?wait=true (or on the settled Operation itself when polled directly). This is a compare-and-swap-style guard against stale-read races -- e.g. two callers racing to wake the same desktop, or a caller acting on a desktop it fetched a while ago and hasn't refreshed since. Omitting expected_generation skips the check entirely.

Fork

POST /v1/desktops/{id}/fork exists in the API surface but always returns 501 Not Implemented -- an honest stub, not a bug. It isn't documented as a working feature anywhere in these docs.

On this page