[http-client-python] Add automatic SSE reconnection - #11904
Libba Lawrence (l0lawrence) wants to merge 12 commits into
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6bf64cba-786a-41ee-8e45-8567e1cf8568
commit: |
|
All changed packages have been documented.
Show changes
|
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6bf64cba-786a-41ee-8e45-8567e1cf8568
|
You can try these changes here
|
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6bf64cba-786a-41ee-8e45-8567e1cf8568
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6bf64cba-786a-41ee-8e45-8567e1cf8568
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6bf64cba-786a-41ee-8e45-8567e1cf8568
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6bf64cba-786a-41ee-8e45-8567e1cf8568
Use the public PipelineClient.send_request API when reconnecting SSE streams so generated Azure clients pass protected-access lint checks. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6bf64cba-786a-41ee-8e45-8567e1cf8568
There was a problem hiding this comment.
🟡 Changes recommended
The reconnect implementation conflicts with the stated azure-core requirement, and event ID header handling has an unresolved bug.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds automatic sync and async SSE reconnection for generated Python clients, including retry delays, event ID resumption, terminal-event handling, and HTTP 204 stopping.
Changes:
- Extends streaming runtimes with reconnection behavior.
- Generates reconnect callbacks through the request and error-mapping pipeline.
- Adds sync/async tests and a feature changelog.
File summaries
| File | Summary |
|---|---|
packages/http-client-python/tests/unit/test_sse_streaming.py |
Tests generated reconnect behavior. |
packages/http-client-python/tests/mock_api/shared/test_streaming_sse.py |
Adds synchronous SSE reconnection coverage. |
packages/http-client-python/tests/mock_api/shared/asynctests/test_streaming_sse_async.py |
Adds asynchronous SSE reconnection coverage. |
packages/http-client-python/generator/pygen/codegen/templates/streaming_base.py.jinja2 |
Adds reconnect runtime behavior. Critical (3 votes): Resolve the requirement to use an azure-core reconnect primitive instead of a generator-vendored loop. |
packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py |
Generates reconnect callbacks. Moderate (2 votes): Omit Last-Event-ID when the event ID buffer is empty. Nit (1 vote each): Add redirect coverage and end-to-end reconnect error-mapping coverage. |
.chronus/changes/http-client-python-sse-reconnection-2026-09-08.md |
Records the feature release change. |
Review details
Suppressed comments (3)
packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py:1405
- The normal operation path deserializes declared custom error responses and attaches them as
HttpResponseError.modelaftermap_error(the logic atbuilder_serializer.py:1170-1274). This reconnect path only callsmap_errorand then raises a bareHttpResponseError, so an unmapped custom or ranged error status during reconnect loses the generated error model and does not follow the operation's normal error behavior.
" map_error(status_code=_reconnect_response.status_code, "
"response=_reconnect_response, error_map=error_map)"
)
retval.append(" raise HttpResponseError(response=_reconnect_response)")
packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py:1394
- The linked requirement also calls out preserving 301/307 redirect handling, but the new sync/async integration tests only exercise 200/204 responses and do not drive a redirect during reconnect. Add a mock-server case for both modes so the generated
send_requestpath and redirect policy are verified rather than only asserted as generated text.
f" _reconnect_response = {self._call_method}self._client.send_request("
"_request, stream=True, **kwargs)"
packages/http-client-python/generator/pygen/codegen/serializers/builder_serializer.py:1403
- The new reconnect-failure branch is only checked as generated text; neither sync nor async tests execute a generated SSE operation that returns a non-success reconnect response and verifies the error mapping. Add an end-to-end generated-client case for this branch, including a custom error response, so this behavior is protected.
retval.append(f" if _reconnect_response.status_code not in {reconnect_status_codes!r}:")
retval.append(f" {self._call_method}_reconnect_response.read()")
retval.append(
" map_error(status_code=_reconnect_response.status_code, "
"response=_reconnect_response, error_map=error_map)"
- Files reviewed: 6/6 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Remove Last-Event-ID from reconnect requests when the SSE ID buffer is empty, including after an empty id field clears a prior value. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6bf64cba-786a-41ee-8e45-8567e1cf8568
…n-sse-reconnection' into l0lawrence-python-sse-reconnection
Move Last-Event-ID mutation into the shared SSE runtime so generated retrieve operations remain within Pylint's statement limit. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6bf64cba-786a-41ee-8e45-8567e1cf8568
Structured SSE streams currently stop at unexpected EOF and require callers to manually resume with
last_event_idthrough an internal workaround. This adds automatic reconnection so generated clients follow the SSE processing model without requiring application-owned reconnect loops.The generated stream runtime now:
retry:value --- Do we want a 3 second default or would we prefer no time delay, just immediately try to reconnect?Last-Event-IDCloses #11761