fix: prevent concurrent R2 mount attempts causing s3fs passwd file co…#202
Open
piffie wants to merge 16 commits intocloudflare:mainfrom
Open
fix: prevent concurrent R2 mount attempts causing s3fs passwd file co…#202piffie wants to merge 16 commits intocloudflare:mainfrom
piffie wants to merge 16 commits intocloudflare:mainfrom
Conversation
…nflict Multiple concurrent requests (e.g. the loading-page waitUntil + the next polling request) can both call mountR2Storage before the first one finishes. Each call to sandbox.mountBucket() appends credentials to the s3fs passwd file, so concurrent calls produce duplicate entries and s3fs refuses to mount with: "there are multiple entries for the same bucket(default) in the passwd file." This adds a module-level in-flight promise that coalesces concurrent mount calls: only the first caller actually attempts the mount, while subsequent callers await the same promise. The lock is released in a finally block so retries are possible after failures. https://claude.ai/code/session_01E5t9gPHDGGrTUWeagkDjVo
fix: prevent concurrent R2 mount attempts causing s3fs passwd file co…
6415c54 to
fb977a8
Compare
Two issues caused the "multiple entries for the same bucket(default) in the passwd file" s3fs error: 1. sandbox.mountBucket() appends credentials to the s3fs passwd file on every call. Because the container persists across Worker invocations (keepAlive / sleepAfter), stale entries from previous mounts accumulate and s3fs refuses to mount. Fix: clear /etc/passwd-s3fs and ~/.passwd-s3fs before each mount attempt. 2. Concurrent requests (e.g. the loading-page waitUntil + the next polling request) can both call mountR2Storage before the first one finishes, producing parallel mountBucket() calls that each append entries. Fix: coalesce concurrent callers behind a single in-flight promise. https://claude.ai/code/session_01E5t9gPHDGGrTUWeagkDjVo
fb977a8 to
ae6e1b3
Compare
…rDsd fix: prevent duplicate s3fs passwd entries on R2 mount
ae6e1b3 to
a0fe7c5
Compare
sandbox.mountBucket() appends credentials to the s3fs passwd file each time it is called. Because the container persists across Worker invocations (keepAlive / sleepAfter), entries accumulate and s3fs refuses to mount with "there are multiple entries for the same bucket(default) in the passwd file." Three-layer fix: 1. Inflight lock — coalesces concurrent callers within the same Worker isolate behind a single in-flight promise, preventing parallel mountBucket() calls. 2. Pre-mount deduplication — runs `sort -u` on s3fs passwd files inside the container before calling mountBucket(), so even if mountBucket appends a duplicate entry it starts from a single-entry (or empty) state. 3. Retry on failure — when mountBucket fails with "multiple entries", deduplicates the passwd file again and retries the s3fs mount directly inside the container (without calling mountBucket again, which would append yet another entry). https://claude.ai/code/session_01E5t9gPHDGGrTUWeagkDjVo
a0fe7c5 to
894f1df
Compare
…rDsd fix: prevent duplicate s3fs passwd entries on R2 mount
|
nice! |
|
validated this resolved the issue on my deployment thanks! |
894f1df to
08ce56d
Compare
…uplication sandbox.mountBucket() manages the s3fs passwd file from the orchestration layer outside the container and appends a new credential entry on every call. Because the container persists across Worker invocations the entries accumulate and s3fs refuses to mount with "multiple entries for the same bucket(default) in the passwd file." In-container cleanup (rm, sort -u) cannot reach the orchestration-layer file. Replace mountBucket() with direct s3fs mounting inside the container, following the pattern from the Cloudflare Containers FUSE-mount docs: 1. Write credentials to /etc/passwd-s3fs via startProcess (overwrite, not append — always exactly one entry) 2. Run s3fs directly inside the container 3. Verify the mount succeeded Credentials are passed via process env vars (R2_KEY, R2_SECRET) to avoid embedding secrets in the command string. The in-flight promise lock is retained to coalesce concurrent callers within the same Worker isolate. https://claude.ai/code/session_01E5t9gPHDGGrTUWeagkDjVo
08ce56d to
20c60fb
Compare
…rDsd fix: replace mountBucket() with direct s3fs mount to prevent passwd d…
20c60fb to
a36283d
Compare
sandbox.startProcess() does not support the env option, so the previous approach of passing R2_KEY/R2_SECRET as process env vars resulted in an empty passwd file (:) that s3fs could not parse. Base64-encode the credentials in TypeScript and decode inside the container instead. https://claude.ai/code/session_01E5t9gPHDGGrTUWeagkDjVo
a36283d to
a1f37dd
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fixes #194
Multiple concurrent requests (e.g. the loading-page waitUntil + the next polling request) can both call mountR2Storage before the first one finishes. Each call to sandbox.mountBucket() appends credentials to the s3fs passwd file, so concurrent calls produce duplicate entries and s3fs refuses to mount with: "there are multiple entries for the same bucket(default) in the passwd file."
This adds a module-level in-flight promise that coalesces concurrent mount calls: only the first caller actually attempts the mount, while subsequent callers await the same promise. The lock is released in a finally block so retries are possible after failures.
https://claude.ai/code/session_01E5t9gPHDGGrTUWeagkDjVo