Skip to content

createBackup() wakes a container that stops after a running-state check #825

Description

@alexminza

Describe the bug

A container can stop after sandbox.getState() reports it as running but before sandbox.createBackup() is called. Because createBackup() automatically starts stopped containers, this race wakes the container and performs a backup that the caller intended to run only while it was already active.

There is no atomic non-waking backup operation equivalent to the established fetchIfRunning() pattern.

To Reproduce

  1. Configure backup support, start a sandbox, and wait until it is running.
  2. Call sandbox.getState() and observe running or healthy.
  3. Stop the container after that state read, representing sleep, eviction, or a crash between the check and the operation.
  4. Call sandbox.createBackup({ dir: "/workspace" }).
  5. Observe that the backup starts the stopped container instead of reporting that it is no longer running.

Expected behavior

Add createBackupIfRunning() as the non-waking counterpart to createBackup(). It should atomically refuse to start a stopped container and return a typed not-running result or error. An equivalent createBackup() option would also solve the gap if maintainers prefer that API shape; the existing auto-start behavior can remain the default.

Screenshots

Not applicable.

  • Version: @cloudflare/sandbox@0.12.1; source behavior reverified in the latest stable @cloudflare/sandbox@0.12.3.

Additional context

The practical impact is low but real: a periodic maintenance consumer can cause an unintended cold start and billed runtime. A state precheck plus an activity-window attempt marker bounds the observed consumer to one unintended wake per activity window, but cannot eliminate the race.

At stable tag @cloudflare/sandbox@0.12.3, BaseTransport.httpFetch() routes requests through containerFetch(), while Sandbox.containerFetch() starts the container when it is not running and healthy.

Related upstream work:

  • sandbox-sdk#415 is the direct predecessor: it requested disabling auto-start for proxyToSandbox(), and maintainers confirmed that request-driven restart is intentional. This request is narrower and not a duplicate because scheduled backup must address the same sandbox and needs an atomic per-operation policy rather than alternate routing.
  • containers#212 proposed fetchIfRunning() as a non-waking primitive. It was closed after sandbox-sdk#708 implemented the same scoped behavior inside the Sandbox SDK for preview URLs. createBackupIfRunning() applies that established naming and behavior to backups.
  • Active sandbox-sdk#819 makes process discovery non-waking. That can remove the need for an exec() readiness probe once released, but createBackup() still has no already-running-only mode.
  • Active containers#148 documents the underlying stop race and intentionally restarts the container when a request arrives while it is stopping. This is why a separate state check cannot provide the requested guarantee.

I searched open and closed issues and pull requests in both repositories for no-wake, no-auto-start, stopped-container, containerFetch, exec, and backup variants. Neither repository has GitHub Discussions enabled.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions