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
- Configure backup support, start a sandbox, and wait until it is running.
- Call
sandbox.getState() and observe running or healthy.
- Stop the container after that state read, representing sleep, eviction, or a crash between the check and the operation.
- Call
sandbox.createBackup({ dir: "/workspace" }).
- 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.
Describe the bug
A container can stop after
sandbox.getState()reports it as running but beforesandbox.createBackup()is called. BecausecreateBackup()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
sandbox.getState()and observerunningorhealthy.sandbox.createBackup({ dir: "/workspace" }).Expected behavior
Add
createBackupIfRunning()as the non-waking counterpart tocreateBackup(). It should atomically refuse to start a stopped container and return a typed not-running result or error. An equivalentcreateBackup()option would also solve the gap if maintainers prefer that API shape; the existing auto-start behavior can remain the default.Screenshots
Not applicable.
@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 throughcontainerFetch(), whileSandbox.containerFetch()starts the container when it is not running and healthy.Related upstream work:
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.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.exec()readiness probe once released, butcreateBackup()still has no already-running-only mode.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.