Conversation
Persist resumable sessions on disk, coordinate upload and object publication with filesystem locks, and publish completed uploads atomically. Add service, server, and Rust client coverage for resuming, cancellation, offset handling, and completion.
This comment was marked as outdated.
This comment was marked as outdated.
Stage each chunk in a temporary file and compare its actual byte count with Content-Length before appending it to the upload session.
Store upload sessions directly under the backend root uploads directory because UUID session names cannot collide with object storage paths.
Write chunks directly into the session so interrupted transfers retain their persisted prefix. Reject and roll back bodies that exceed Content-Length.
Cap each resumable write at the advertised content length without failing when the source stream contains more data.
Keep any bytes appended before a resumable chunk write fails. Sync the partial session once, then preserve the distinction between client-stream and backend errors.
Move capped chunk writes and syncing into UploadFile. Simplify put_chunk to return early for incomplete uploads and publish directly once the stored payload reaches its total length.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 608dae8. Configure here.
| }) | ||
| } | ||
| } |
There was a problem hiding this comment.
Bug: A race condition between upload finalization and a progress query can cause the query to incorrectly fail with an UploadSessionGone error, leading the client to restart a successful upload.
Severity: MEDIUM
Suggested Fix
The upload lock should be held continuously throughout the entire finalization process. Avoid dropping the upload_guard and re-acquiring a new lock. Instead, maintain the lock from before the final chunk write until after the file rename is complete to prevent other operations from observing the intermediate state.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: objectstore-service/src/backend/local_fs.rs#L394-L396
Potential issue: A race condition exists during the finalization of a multipart upload.
There is a brief window between when the final chunk is written to disk and when the
upload is officially published by renaming the file. In this window, the upload lock is
temporarily released and re-acquired. If a client sends a progress query
(`upload_offset`) during this exact moment, the query will find the upload file is
complete but not yet published. This causes the `upload_offset` function to incorrectly
return an `UploadSessionGone` error (HTTP 410). The client will interpret this as a
permanent failure and restart the entire upload, even though the original upload was on
the verge of successful completion.
Did we get this right? 👍 / 👎 to inform future reviews.
Use underscore-prefixed LockGuard fields to express that retaining file ownership holds the flock, removing the broad dead-code allowance.
Move session creation, offset access, and publication into UploadFile. Share metadata preamble encoding with normal object drafts while keeping lock orchestration in the backend.
Record resumable publications in the change stream with their full on-disk size and expiry after the atomic rename succeeds.
Serialize each object's resumable sessions with its existing mutation lock and remove the dual-lock publication path.
Construct the byte-limited request reader in put_chunk while preserving partial writes and client-stream error propagation in UploadFile::append.
Match the object lock path and acquisition helpers to main, and mark the behavioral phases of the resumable LocalFS tests.

The LocalFS backend now implements resumable uploads.
In-progress uploads are persisted in
uploads/<upload id>, where the upload ID is a UUID v7.This requires adapting the filesystem locking machinery to lock either the object or the session file or both.
We now resolve the TODO comments in the server and Rust client by adding end-to-end test coverage.