Skip to content

Add end-to-end response streaming via streamRequest()#2

Merged
loks0n merged 1 commit into
mainfrom
feat/end-to-end-streaming
Jun 6, 2026
Merged

Add end-to-end response streaming via streamRequest()#2
loks0n merged 1 commit into
mainfrom
feat/end-to-end-streaming

Conversation

@loks0n

@loks0n loks0n commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Add streamRequest(RequestInterface, callable $sink) to the Adapter interface, the Client wrapper, and both transports. It delivers the response body to the sink chunk-by-chunk as it arrives, keeping memory bounded regardless of body size; the returned response carries the status and headers with an empty body.

Both adapters use their native push mechanism in the calling context — no curl_multi, no child coroutine:

  • cURL forwards CURLOPT_WRITEFUNCTION to the sink (sendRequest and streamRequest now share a transfer() core).
  • Swoole forwards write_func to the sink in the main coroutine (sendRequest/streamRequest share perform()).

sendRequest() is unchanged: still PSR-18, buffered, decodable.

Tests (shared AdapterContract, so proven on curl and Swoole):

  • stream a body to a sink, asserting incremental delivery
  • 8 MiB request and response payloads round-trip; the streamed response holds peak memory under 2 MiB
  • redirects are not followed when streaming The test server now runs with post_max_size=64M/memory_limit=256M so large request payloads are accepted.

Add streamRequest(RequestInterface, callable $sink) to the Adapter
interface, the Client wrapper, and both transports. It delivers the
response body to the sink chunk-by-chunk as it arrives, keeping memory
bounded regardless of body size; the returned response carries the
status and headers with an empty body.

Both adapters use their native push mechanism in the calling
context — no curl_multi, no child coroutine:
- cURL forwards CURLOPT_WRITEFUNCTION to the sink (sendRequest and
  streamRequest now share a transfer() core).
- Swoole forwards write_func to the sink in the main coroutine
  (sendRequest/streamRequest share perform()).

sendRequest() is unchanged: still PSR-18, buffered, decodable.

Tests (shared AdapterContract, so proven on curl and Swoole):
- stream a body to a sink, asserting incremental delivery
- 8 MiB request and response payloads round-trip; the streamed
  response holds peak memory under 2 MiB
- redirects are not followed when streaming
The test server now runs with post_max_size=64M/memory_limit=256M so
large request payloads are accepted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@loks0n loks0n merged commit 1082a15 into main Jun 6, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant