Support streaming put payloads - #817
Conversation
|
There is more rationale for non streaming APIs here:
TLDR is that streaming writes make a bunch of other operations (like retry , error handling, etc) |
|
I see you have talked about multi-part uploads here: #281 (comment) |
It's not the same because of costs. Uploading a 64Mb file in a single put request is still quite fast (depending on your needs) and you are charged for 1 request. If you upload 64 different 1Mb parts, you are charged by the initial request, 64 parts individually and 1 final requests. So it's 66 times more expensive. You can check the link in this comment: #281 (comment) |
tustvold
left a comment
There was a problem hiding this comment.
I think the idea is a good one, but as Andrew says we need to think about how retries, etc... would work
| fn clone(&self) -> Self { | ||
| Self { | ||
| payload: self.payload.clone(), | ||
| stream: None, |
There was a problem hiding this comment.
This would likely be rather limiting in practice as it would break retries in client implementations
|
There is a bunch more discussion on #281 now too |


Which issue does this PR close?
Closes #281.
Rationale for this change
PutPayloadcurrently only supports collections ofBytes. As a result, uploading a file throughputorput_optsrequires loading the entire file into memory or using a multipart upload.This change allows callers to stream a payload with a known content length through a single PUT request. File-backed payloads are a primary use case.
What changes are included in this PR?
PutPayloadto support replayable streaming bodies with a known content length.PutPayload::from_streamfor constructing streaming payloads.PutPayload::from_file, which reads files in 16 KiB chunks by default.PutPayload::from_file_with_chunk_sizefor configuring the file chunk size.Validation performed:
cargo testcargo test --all-featurescargo clippy --all-targets --all-features -- -D warningsfsfeatureAre there any user-facing changes?
Yes. Callers can now upload a file without first loading the complete file into memory:
Custom streaming payloads can be created with PutPayload::from_stream. The stream factory must produce a new stream from the beginning for every invocation, and the
supplied content length must exactly match the number of bytes yielded.
Existing byte-backed PutPayload construction and iteration behavior is unchanged. Synchronous APIs such as iter, AsRef<[Bytes]>, and conversion into Bytes are not supported for streaming payloads; callers should use PutPayload::stream or PutPayload::bytes instead.
API compatibility consideration
PutPayloadremains a public struct backed by a private enum so that existing byte-backed construction and usage remain source compatible:There is an API-design limitation around the existing synchronous accessors. Methods and trait implementations such as PutPayload::iter, AsRef<[Bytes]>, IntoIterator, and conversion into Bytes cannot synchronously represent an asynchronous, fallible stream.
In this implementation, their existing behavior is unchanged for byte-backed payloads, but calling them with a streaming payload panics. Streaming-aware implementations should instead use PutPayload::stream or PutPayload::bytes.
Changing the existing synchronous APIs to return Option or Result would avoid the panic but would be a breaking public API change. Returning an empty iterator for streaming payloads was rejected because it could silently result in incomplete uploads.
Feedback from maintainers on the preferred long-term API shape would be appreciated. Possible alternatives include: