-
Notifications
You must be signed in to change notification settings - Fork 81
fix: address review comments from PRs #2604 and #2619 #2634
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,6 +57,15 @@ class WSBroadcaster(EventConsumer): | |
| consumer_id: str = "ws_broadcaster" | ||
|
|
||
| def __init__(self, consumer_id: str | None = None) -> None: | ||
| """Initialize the broadcaster. | ||
|
|
||
| Args: | ||
| consumer_id: Optional unique identifier used when subscribing to | ||
| the session event bus. Defaults to the class-level | ||
| ``"ws_broadcaster"``. Pass a unique value (e.g. per | ||
| reconnect-replay connection) so concurrent broadcasters on the | ||
| same bus do not overwrite each other's subscriptions. | ||
| """ | ||
| self.consumer_id = consumer_id or self.consumer_id | ||
| self._connections: dict[str, _ConnectionInfo] = {} | ||
| self._bus: SessionEventBus | None = None | ||
|
|
@@ -195,3 +204,52 @@ def _passes_filter(kind: AgentEventKind, verbosity: str) -> bool: | |
| return kind in _SUMMARY_KINDS | ||
| # Unknown verbosity -- default to full | ||
| return True | ||
|
|
||
|
|
||
| async def start_reconnect_replay( | ||
| bus: SessionEventBus, | ||
| *, | ||
| conn_id: str, | ||
| send_callback: SendCallback, | ||
| from_sequence: int, | ||
| ) -> WSBroadcaster: | ||
| """Create and start a dedicated broadcaster that replays missed events. | ||
|
|
||
| Used on WebSocket reconnect: a per-connection broadcaster (unique | ||
| ``consumer_id`` so concurrent reconnects don't clobber each other's bus | ||
| subscriptions) is subscribed to *bus* and replays buffered events from | ||
| *from_sequence* to *send_callback*. Callers must pair this with | ||
| :func:`stop_reconnect_replay` on disconnect. | ||
| """ | ||
| broadcaster = WSBroadcaster(consumer_id=f"ws_broadcaster:{conn_id}") | ||
| await broadcaster.start(bus) | ||
| await broadcaster.add_connection( | ||
| conn_id=conn_id, | ||
| send_callback=send_callback, | ||
| from_sequence=from_sequence, | ||
| ) | ||
| return broadcaster | ||
|
Comment on lines
+209
to
+264
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If async def start_reconnect_replay(
bus: SessionEventBus,
*,
conn_id: str,
send_callback: SendCallback,
from_sequence: int,
) -> WSBroadcaster:
"""Create and start a dedicated broadcaster that replays missed events.
Used on WebSocket reconnect: a per-connection broadcaster (unique
``consumer_id`` so concurrent reconnects don't clobber each other's bus
subscriptions) is subscribed to *bus* and replays buffered events from
*from_sequence* to *send_callback*. Callers must pair this with
:func:`stop_reconnect_replay` on disconnect.
"""
broadcaster = WSBroadcaster(consumer_id=f"ws_broadcaster:{conn_id}")
await broadcaster.start(bus)
try:
await broadcaster.add_connection(
conn_id=conn_id,
send_callback=send_callback,
from_sequence=from_sequence,
)
except Exception:
await broadcaster.stop()
raise
return broadcaster
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in dd8660b: add_connection is now wrapped so a mid-replay failure stops the broadcaster (best-effort, logged) before re-raising; regression test test_start_reconnect_replay_cleans_up_when_registration_fails asserts no leaked bus subscriber.
qodo-code-review[bot] marked this conversation as resolved.
|
||
|
|
||
|
|
||
| async def stop_reconnect_replay(broadcaster: WSBroadcaster, conn_id: str | None) -> None: | ||
| """Tear down a reconnect-replay broadcaster created by :func:`start_reconnect_replay`. | ||
|
|
||
| Cleanup failures are logged (never silently suppressed) but do not | ||
| propagate: this runs in disconnect paths where raising would mask the | ||
| original connection error. | ||
| """ | ||
| if conn_id is not None: | ||
| try: | ||
| broadcaster.remove_connection(conn_id) | ||
| except Exception as exc: | ||
| logger.warning( | ||
| "Failed to remove reconnect replay connection {}: {}", conn_id, exc | ||
| ) | ||
| try: | ||
| await broadcaster.stop() | ||
| except Exception as exc: | ||
| logger.warning( | ||
| "Failed to stop reconnect replay broadcaster {}: {}", | ||
| broadcaster.consumer_id, | ||
| exc, | ||
| ) | ||
|
qodo-code-review[bot] marked this conversation as resolved.
Outdated
|
||
Uh oh!
There was an error while loading. Please reload this page.