Skip to content

fix(ops): upload the R2 weekly archive as multipart parts, not one PUT - #1911

Merged
jaywedgeworth22 merged 2 commits into
mainfrom
Muse-Assist/r2-archive-multipart-upload
Nov 8, 2026
Merged

jaywedgeworth22 merged 2 commits into
mainfrom
Muse-Assist/r2-archive-multipart-upload

Conversation

@jaywedgeworth22

@jaywedgeworth22 jaywedgeworth22 commented Nov 8, 2026 •

Copy link
Copy Markdown
Member
  • The gzip is stream-hashed (SHA-256) instead of being read whole into memory.

Replaces the single-PUT R2 weekly archive upload with S3 multipart upload using ~64 MB parts. The change is motivated by two mid-transfer failures on 2026-11-07 where a dropped connection voided an ~1.5 GB transfer that had to restart from byte zero. Each part is individually signed and retried up to 3 times, so a dropped connection costs one part rather than the full object, and an unrecoverable failure issues AbortMultipartUpload so no orphan parts linger. The archive flow now hashes the gzip via streaming and reads parts from disk, avoiding holding the full gzip in memory, while preserving metadata on CreateMultipartUpload and the existing download-back verify of re-hash, decompress, and integrity_check before pruning. Create and complete failures are remapped to preserve the prior upload_failed classification, and a 200 response carrying an S3 <Error> body on CompleteMultipartUpload is treated as failure. Tests added cover sequential part assembly, retry after a dropped connection, and abort preserving the signer error, with the in-memory S3 stub extended for multipart lifecycle; live transfer behavior remains unverified here. Automated review reports one unresolved medium finding: invalid partBytes causes an infinite multipart upload loop in uploadMultipart.

The weekly archive (~1.5 GB gzip) went up as a single signed PUT.  Twice on 2026-11-07 the transfer died mid-flight with UND_ERR_SOCKET after several minutes and the run reported upload_failed — snapshot, verification, and compression all succeeded; only the single-shot transfer failed, and one dropped connection voided the whole upload.

Replace it with an S3 multipart upload built on the existing hand-rolled signer: CreateMultipartUpload carries the sha256/source-bytes/created-at metadata, parts of ~64 MB are read from the gzip file one at a time (the file is stream-hashed first; it is never loaded into memory), each part is retried up to 3 times, CompleteMultipartUpload sends the part ETag list, and AbortMultipartUpload runs on any unrecoverable failure.  A 200-with-<Error> completion body is treated as the failure it is.  Failure messages keep the S3 PUT prefix so classifyFailure still reports upload_failed.

Unchanged: env vars, bucket/prefix/key naming, status-file shape and reasons, the download-back verification (hash + gunzip + integrity_check + embedded sha), prune behavior, the kill switch, and exit codes.  The download-back GET stays a single streamed read — splitting it is a separate change if it ever becomes the failure point.

Tests: the in-memory S3 stub learns multipart (create/parts/complete/abort); the upload-transport-rejection test now expects create + 3 part attempts + abort; three new uploadMultipart tests cover multi-part assembly, retry of a dropped part, and abort with the signer error preserved.  npm run test:r2-archive: 28 passed.

Refs UM-1538.
@kody-ai

kody-ai Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

Code Review Completed! 🔥

The code review was successfully completed based on your current configurations.

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug ✅
Performance ✅
Security ✅
Business Logic ✅

Access your configuration settings here.

​

Comment thread scripts/ops/r2-weekly-archive.mjs Resolved
uploadMultipart never validated partBytes: 0 makes partCount Infinity and the part loop issues empty PUTs forever instead of failing.  Validate partBytes as a positive integer and fileBytes as a non-negative integer before CreateMultipartUpload, with a test asserting no S3 call happens.  29 tests pass.
@jaywedgeworth22
jaywedgeworth22 merged commit 3c93e5d into main Nov 8, 2026
20 checks passed
@jaywedgeworth22
jaywedgeworth22 deleted the Muse-Assist/r2-archive-multipart-upload branch November 8, 2026 03:53
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