Repository navigation
Response Streaming Implementation Plan #9
Replies: 2 comments
Update:
|
|
Streaming responses have been implemented. The architecture evolved significantly from this plan — there is no What was implemented:
See discussion #8's closing comment for more detail on the design differences. |
Uh oh!
There was an error while loading. Please reload this page.
Implementation plan for response streaming (design: #8). Request body streaming is deferred.
Scope
Add opt-in streaming response support so any handler can send chunked HTTP responses. The existing buffered response path is unchanged.
New Files
hobby/stream_sender.ponyNo wrapper actor needed.
_Connectionstructurally matches this interface by havingsend_chunkandfinishbehaviors.Context.start_streaming()returns_Connection tagupcast toStreamSender tag. Users can't name_Connection(package-private), so no extra capabilities leak.Modified Files
hobby/context.ponylet _conn: _Connection tagvar _streaming: Bool = falseconn: _Connection tagparameterstart_streamingmethod:is_streamingmethod:_finish_streamingmethod for error cleanup:HTTP/1.0 behavior:
start_streamingchecksrequest.version. For HTTP/1.0, it skips_handled/_streaming/start_chunked_responseentirely. The returnedStreamSenderis a no-op (because_Connection._streaming_responderis never set). The chain runner seesis_handled() == falseafter the handler returns and sends 500. The client gets a response rather than a hanging connection.hobby/_connection.ponyvar _streaming_responder: (stallion.Responder | None) = Noneon_request_complete— passthisto Context constructor and store the responder after_ChainRunnercompletes if streaming was started:hobby/_chain_runner.ponyUpdate handler phase and middleware
beforephase to clean up partial streams on error. If a handler (or middleware) callsstart_streaming()then errors before setting up its chunk-producing actor, the stream would hang. The chain runner finishes it:Handler phase:
Middleware
beforephase:hobby/_test_integration.ponyAdd integration tests and register them in
_TestIntegrationList.tests():_TestStreamingResponse— A_StreamingTestHandlerstarts streaming and creates a_TestChunkProduceractor with theStreamSender. The producer sends "chunk1" and "chunk2" then callsfinish(). The test client's expected string is "chunk2" (which only appears after both chunks are sent, confirming the stream was properly started and terminated — the test completes within the timeout becausefinish()sends the terminal chunk and closes the response cleanly)._TestStreamingErrorCleanup— A handler starts streaming then raiseserror. The chain runner calls_finish_streaming(), which sends the terminal chunk. Verification is by test completion: if the cleanup didn't happen, the connection would hang and the test would time out. The expected string is"Transfer-Encoding: chunked"to confirm the chunked response machinery ran.hobby/hobby.pony(package docstring)Add a "Streaming Responses" section after the Middleware section:
examples/streaming/(new)SSE-style example demonstrating:
ctx.start_streaming()StreamSender tagto a producer actorexamples/README.mdAdd entry for the streaming example.
CLAUDE.mdstream_sender.ponyto File LayoutStreamSenderto Public API sectionRelease Notes
Classify as added (new feature). Create release notes file per project conventions.
Implementation Order
stream_sender.pony— the interface (no dependencies)context.pony— add_connfield,start_streaming,is_streaming,_finish_streaming_connection.pony— add streaming field, behaviors, updateon_request_complete_chain_runner.pony— error cleanup for partial streams_test_integration.pony— streaming integration tests + register in_TestIntegrationListexamples/streaming/— example programexamples/README.md— updatehobby.pony— update package docstringCLAUDE.md— update architecture docsKnown Limitations
One streaming response per connection at a time.
_Connectionstores a single_streaming_responderfield. If HTTP/1.1 keep-alive delivers a second request while a streaming response to the first is still in progress, and the second request also starts streaming, the responder field is overwritten. In practice clients don't pipeline streaming requests, but this is a correctness limitation. A future enhancement could use a keyed map of responders indexed by Stallion's request ID.Build and Test
All reactions