Rindle.Storage.S3 (Rindle v0.1.8)

Copy Markdown View Source

S3-compatible storage adapter powered by ExAws.

tus single-node constraint

The S3 tus backing (upload_part_stream/5) buffers each PATCH's sub-5-MiB tail remainder on node-local disk under Rindle.tmp/tus/, while the authoritative cross-PATCH bookkeeping (offset, upload_id, committed parts) lives in the shared DB. Because the tail buffer is node-local, the S3 tus backing REQUIRES single-node or sticky-session routing: a resumed PATCH must reach the same node that holds the in-progress tail buffer.

A cross-node resume — where the DB implies buffered bytes (a non-empty upload_id together with EITHER at least one committed part OR a persisted offset greater than length(parts) * @s3_min_part_size) but the expected tail file is absent on this node — is detected and fails loudly with {:error, :tus_tail_missing} rather than silently re-slicing from a fresh empty tail (which would corrupt the assembled object). This covers the pre-first-part window too: a first PATCH under 5 MiB buffers a node-local tail without committing any part (parts: [], offset > 0), so a misrouted resume in that window also fails loudly instead of dropping the buffered bytes. A brand-new FIRST PATCH (offset == 0) is never falsely guarded. Multi-node operators MUST pin tus PATCHes to a single node (sticky sessions) or accept this loud failure on misrouted resumes.

Summary

Functions

Canonical reaper-facing path of the on-disk tail buffer for a tus session.

Functions

tus_tail_path(session_id, opts \\ [])

@spec tus_tail_path(
  binary(),
  keyword()
) :: Path.t()

Canonical reaper-facing path of the on-disk tail buffer for a tus session.

Returns the EXACT file upload_part_stream/5 writes its sub-5-MiB tail remainder to for session_id, so cleanup code (the orphan reaper / Rindle.Ops.UploadMaintenance) can delete the real file rather than guessing at the encoding. The adapter owns the one canonical tail-path computation here: the path is Base.url_encode64(session_id, padding: false) <> ".tail" under the sweepable Rindle.tmp/tus/ root — never the raw id (CR-02).

Pass :root to override the base dir (used by tests for per-test isolation). Delegates to the private tail_path/2, threading session_id as both the key and the :session_id opt so the encoding is identical regardless of how the original PATCH was keyed. There is exactly one Base.url_encode64 site (tail_filename/1); this helper does not re-encode.