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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions