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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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