Skip to content

Fix local bucket mount synchronization - #890

Open
scuffi wants to merge 1 commit into
nextfrom
fix/864-local-mount-next
Open

Fix local bucket mount synchronization#890
scuffi wants to merge 1 commit into
nextfrom
fix/864-local-mount-next

Conversation

@scuffi

@scuffi scuffi commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Local bucket mounts could fail on large files, lose updates after transient R2 errors, or remain tied to a replaced container runtime.

  • Stream R2 downloads and raw container reads without base64 control-frame limits.
  • Upload fixed-size multipart parts, cancel abandoned streams, and keep shutdown bounded when transfers stall.
  • Debounce and serialize filesystem changes, retry failed uploads/deletes, and preserve failed poll operations for retry.
  • Suppress only active atomic-write temporary paths and keep overlapping echo suppression ordered.
  • Treat identical active mounts as no-ops and replace stale mounts through the current runtime lease.

Resolves #864 on next.

Validation

  • Final gate review: NO FINDINGS
  • npm run check: 23/23 tasks
  • Sandbox suite: 65 files, 1,080 tests
  • Shared suite: 7 files, 120 tests
  • Focused container file-service suite: 52 tests

@changeset-bot

changeset-bot Bot commented Aug 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 450d1b9

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cloudflare/sandbox Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Aug 28, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@cloudflare/sandbox@890

commit: 450d1b9

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

🐳 Docker Images Published

Variant Image
Default cloudflare/sandbox:0.0.0-pr-890-450d1b9f
Python cloudflare/sandbox:0.0.0-pr-890-450d1b9f-python
OpenCode cloudflare/sandbox:0.0.0-pr-890-450d1b9f-opencode
Musl cloudflare/sandbox:0.0.0-pr-890-450d1b9f-musl

Usage:

FROM cloudflare/sandbox:0.0.0-pr-890-450d1b9f

Version: 0.0.0-pr-890-450d1b9f


📦 Standalone Binary

For arbitrary Dockerfiles:

COPY --from=cloudflare/sandbox:0.0.0-pr-890-450d1b9f /container-server/sandbox /sandbox
ENTRYPOINT ["/sandbox"]

Download via GitHub CLI:

gh run download 33654241059 -n sandbox-binary

Extract from Docker:

docker run --rm cloudflare/sandbox:0.0.0-pr-890-450d1b9f cat /container-server/sandbox > sandbox && chmod +x sandbox

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

🔍 Devin Review: 1 flag

Not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

@scuffi
scuffi force-pushed the fix/864-local-mount-next branch 4 times, most recently from db26341 to 6d8d6fe Compare August 28, 2026 13:34
Large transfers and runtime replacement could leave local R2 mounts stuck
or lose pending changes. Stream transfers, retry serialized updates, and
bind mount synchronization to the active runtime.
@scuffi
scuffi force-pushed the fix/864-local-mount-next branch from 6d8d6fe to 450d1b9 Compare September 2, 2026 16:19

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

2 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

Comment on lines +294 to +296
await this.withEchoSuppression(containerPath, () =>
this.transferR2ObjectToContainer(key, containerPath, generation)
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Pending local edits get overwritten

While a local upload is pending, pollR2ForChanges can replace the newer local file with the previous upload. The delayed upload republishes old bytes, losing the edit.

Prompt for agents
LocalMountSyncManager serializes transfers but pollR2ForChanges does not honor pathIntentVersions. If upload A is active, a second filesystem event records intent B, and a poll queues before B's debounce expires, the poll can observe A in R2 while the snapshot still represents the pre-A object. It then writes A back over local B; B's delayed upload reads A and permanently loses B. Update pollR2ForChanges to avoid applying R2 modifications or deletions for container paths with an active local intent. Preserve retry behavior and define how the skipped R2 state is revisited after the local intent finishes.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +135 to +139
const settle = (async () => {
if (this.uploadTimers.size > 0) {
await delay(UPLOAD_DEBOUNCE_MS);
}
await this.transferQueue;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Stop drops late upload retries

An upload failure during stop can schedule its retry after transferQueue settles. interrupt clears that retry, so unmounting can discard the final change.

Prompt for agents
LocalMountSyncManager.stop checks uploadTimers only once, then awaits transferQueue. An active transfer can reject while stop is waiting; scheduleUploadAttempt handles that rejection outside transferQueue and creates a retry timer. Stop then finishes settling and interrupt clears that timer. Make graceful stop track retry handlers and newly scheduled retry timers until no admitted upload intent remains, subject to stopTimeoutMs. Ensure timeout still aborts stalled streams and releases the runtime hold.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant