Skip to content

[http-client-python] Add automatic SSE reconnection - #11904

Draft
Libba Lawrence (l0lawrence) wants to merge 12 commits into
microsoft:mainfrom
l0lawrence:l0lawrence-python-sse-reconnection
Draft

Libba Lawrence (l0lawrence) wants to merge 12 commits into
microsoft:mainfrom
l0lawrence:l0lawrence-python-sse-reconnection

Conversation

@l0lawrence

@l0lawrence Libba Lawrence (l0lawrence) commented Sep 9, 2026

Copy link
Copy Markdown
Member

Structured SSE streams currently stop at unexpected EOF and require callers to manually resume with last_event_id through 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:

  • reconnects after unexpected EOF using the default three-second delay or the latest valid retry: value --- Do we want a 3 second default or would we prefer no time delay, just immediately try to reconnect?
  • preserves and sends the latest event ID through Last-Event-ID
  • stops reconnecting after terminal events and HTTP 204 responses (per the spec)
  • routes reconnect failures through the generated operation's normal error mapping
  • supports both sync and async streams

Closes #11761

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6bf64cba-786a-41ee-8e45-8567e1cf8568
@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:client:python Issue for the Python client emitter: @typespec/http-client-python label Sep 9, 2026
@pkg-pr-new

pkg-pr-new Bot commented Sep 9, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-python@11904

commit: 150af5a

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @typespec/http-client-python
Show changes

@typespec/http-client-python - feature ✏️

Automatically reconnect SSE streams after an unexpected disconnect, honoring server-provided retry delays and resuming with the latest event ID.,> ,> python,> with client.events.stream() as stream:,> for event in stream:,> print(event),>

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6bf64cba-786a-41ee-8e45-8567e1cf8568
@azure-sdk-automation

azure-sdk-automation Bot commented Sep 9, 2026

Copy link
Copy Markdown

You can try these changes here

🛝 Playground 🌐 Website 🛝 VSCode Extension

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.model after map_error (the logic at builder_serializer.py:1170-1274). This reconnect path only calls map_error and then raises a bare HttpResponseError, 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_request path 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:python Issue for the Python client emitter: @typespec/http-client-python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[http-client-python] Add SSE reconnection

3 participants