Skip to content

Support streaming request bodies to avoid buffering large uploads in memory #972

Description

@vdusek

File-like values passed to KeyValueStoreClient.set_record (and Actor run inputs) are fully read into memory by value.read() in encode_key_value_store_record_value, and _prepare_request_call then compresses the whole buffer into a second full copy. Uploading a large record (e.g. multi-GB) from a file handle needs ~2x its size resident in RAM.

Root cause

There is no chunked/streaming path anywhere in the stack:

  • HttpClient.call / HttpClientAsync.call type the body as data: str | bytes | bytearray | None — no iterator or file object.
  • HttpClientBase._prepare_request_call reads the whole data and compresses it in one shot: self._http_compressor.compress(data) runs over the full buffer, regardless of the configured HttpCompressor (applies to both gzip and brotli).
  • The default transport (ImpitHttpClient) only accepts a bytes-like content= body.

Notes on a fix

Full streaming requires changes across the whole layer, not just the transport:

  1. Accept a streaming body (bytes iterator / async iterator / file object) through the HttpClient abstraction.
  2. Make compression incremental or skippable, so the body is not re-buffered. This has to hold for every HttpCompressor implementation (gzip and brotli), not a single one.
  3. Use a transport that can stream the body. httpx supports this today — content= accepts a sync/async bytes generator and streams it chunk-by-chunk (multipart uploads via files= stream by default). It is unclear whether impit exposes an equivalent; that needs checking, and impit was chosen for its browser-like TLS fingerprints, so swapping transports has trade-offs.

Follow-up to commit bc092b8 (file-like read fix), where this was noted as out of scope.

✍️ Drafted by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request.t-toolingIssues with this label are in the ownership of the tooling team.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions