Skip to content

✨ feat(storage): add an S3-compatible blob backend#605

Merged
gaborbernat merged 1 commit into
tox-dev:mainfrom
gaborbernat:feat/s3-blob-backend-487
Jul 18, 2026
Merged

✨ feat(storage): add an S3-compatible blob backend#605
gaborbernat merged 1 commit into
tox-dev:mainfrom
gaborbernat:feat/s3-blob-backend-487

Conversation

@gaborbernat

Copy link
Copy Markdown
Member

Blobs currently live only on a node's local filesystem, tying capacity and durability to one disk. Issue #487 asks for an S3-compatible backend behind the capability boundary that #586 introduced, so an operator can keep content in an object store while metadata stays in redb. 📦

The backend implements the shared BlobBackend contract over a small SigV4-signed REST client built on the reqwest and rustls the workspace already depends on, instead of pulling in the full AWS SDK. Because a blob's key is its sha256, a streamed write stages to a local temp file and hashes as it goes: the digest is known before anything reaches S3, and readers can still tail an in-progress stage. Commit uploads under <prefix>/sha256/<digest> with a single PUT below multipart_threshold_bytes and bounded concurrent parts above it, aborting the multipart upload on failure so orphaned parts do not linger. Reads stream ranged GETs and verify against the digest. The declared capabilities match what the backend does: native range, checksum, and delete; create-if-absent emulated through idempotent content-addressed writes; and no listing. The blocking maintenance facade stays filesystem-only. 🔒

Selection lives in a new [blob] config table, validated through the backend's own builder so configuration and runtime agree on what is usable. Credentials never enter configuration or logs: they resolve from AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and the optional AWS_SESSION_TOKEN at startup, and selecting S3 without them fails fast. peryx backup snapshots the selection but never the secrets. The filesystem backend remains the default, so existing deployments are unaffected.

@gaborbernat gaborbernat added enhancement New feature or request type:feature New user-facing or protocol capability area:performance Cache, HTTP, memory, and benchmark work labels Jul 18, 2026
@gaborbernat

Copy link
Copy Markdown
Member Author

Closes #487

@read-the-docs-community

read-the-docs-community Bot commented Jul 18, 2026

Copy link
Copy Markdown

@gaborbernat
gaborbernat force-pushed the feat/s3-blob-backend-487 branch from 42bbea9 to 47610f9 Compare July 18, 2026 02:03
@codspeed-hq

codspeed-hq Bot commented Jul 18, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 32 untouched benchmarks
⏩ 94 skipped benchmarks1


Comparing gaborbernat:feat/s3-blob-backend-487 (3e97aae) with main (907d1f8)

Open in CodSpeed

Footnotes

  1. 94 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@gaborbernat
gaborbernat force-pushed the feat/s3-blob-backend-487 branch from 47610f9 to 7f9490f Compare July 18, 2026 02:24
Blobs so far lived only on the local filesystem, which ties a node's
capacity and durability to one disk. Issue tox-dev#487 asks for an
S3-compatible backend behind the capability boundary tox-dev#586 established so
an operator can keep content in an object store while metadata stays in
redb.

The backend implements the shared BlobBackend contract over a minimal
SigV4-signed REST client built on the reqwest and rustls the workspace
already uses, rather than pulling the full AWS SDK. A streamed write
stages to a local temp file and hashes as it goes, so the digest is
known before anything reaches S3 and readers can still tail an
in-progress stage; commit uploads under the digest key with one PUT
below the multipart threshold and bounded concurrent parts above it,
aborting the upload on failure so parts do not linger. Reads stream
ranged GETs and verify against the digest. Capabilities are declared for
what the backend actually does: native range, checksum, and delete;
emulated create-if-absent via idempotent content-addressed writes; no
listing. The blocking maintenance facade stays filesystem-only.

Selection moves into the [blob] config table, validated through the
backend's own builder. Credentials never enter configuration or logs;
they resolve from the standard AWS environment variables at startup, and
a missing key fails fast. Backup snapshots the selection but not the
secrets.

Tests drive the client against an in-process wiremock S3 double covering
put, get, range, head, verify, delete, multipart, retries, aborts, and
malformed responses, with a known-answer SigV4 vector, so nothing hits a
real bucket.
@gaborbernat
gaborbernat force-pushed the feat/s3-blob-backend-487 branch from 7f9490f to 3e97aae Compare July 18, 2026 03:11
@gaborbernat
gaborbernat enabled auto-merge (squash) July 18, 2026 03:17
@gaborbernat
gaborbernat merged commit f84e85e into tox-dev:main Jul 18, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:performance Cache, HTTP, memory, and benchmark work enhancement New feature or request type:feature New user-facing or protocol capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant