Exit early if trying to close the peer connections twice#234
Conversation
Previously, the repeated close() calls were hanging indefinitely for PublisherPeerConnection and SubscriberPeerConnection. Now, we set `_closed=True` guard after the connection is closed for the first time and exit early on the repeated call.
📝 WalkthroughWalkthroughAdded idempotent Changes
Sequence Diagram(s)sequenceDiagram
participant CM as ConnectionManager
participant Reconnect as _reconnect_migrate
participant Connector as _connect_internal
participant OldCleanup as _cleanup_connections
CM->>Reconnect: start migrate
Reconnect->>CM: clear CM.publisher_pc / CM.subscriber_pc
Reconnect->>CM: set state = MIGRATING
Reconnect->>Connector: invoke _connect_internal (creates new PCs)
Connector-->>CM: new publisher_pc / subscriber_pc set
Reconnect->>OldCleanup: leave old instances for cleanup
OldCleanup->>OldCleanup: cleanup old peer connections asynchronously
sequenceDiagram
participant SubPC as SubscriberPeerConnection
participant Drain as VideoDrainTask
participant Proxy as DrainProxy
participant Blackhole as MediaBlackhole
SubPC->>SubPC: if _closed True -> return
SubPC->>Drain: cancel each drain task
SubPC->>Proxy: stop each drain proxy
SubPC->>Blackhole: await blackhole.stop()
SubPC->>SubPC: cancel background tasks, clear maps
SubPC->>SubPC: set _closed = True
SubPC->>Super: await super().close()
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
getstream/video/rtc/pc.py (1)
258-281: Consider wrapping cleanup in try/except to ensuresuper().close()is always called.If
await blackhole.stop()raises an exception,super().close()andself._closed = Trueare never executed. This could leave the underlying RTCPeerConnection unclosed, and subsequent close() calls will retry the same failing cleanup.🛡️ Proposed defensive cleanup
async def close(self): # Using self._closed guard here # to avoid closing RTCPeerConnectionTwice by accident (it freezes on second time) if self._closed: return # Clean up video drains for blackhole, drain_task, drain_proxy in list(self._video_drains.values()): - drain_task.cancel() - drain_proxy.stop() - await blackhole.stop() + try: + drain_task.cancel() + drain_proxy.stop() + await blackhole.stop() + except Exception as e: + logger.warning(f"Error cleaning up video drain: {e}") self._video_drains.clear() # Cancel background tasks for task in list(self._background_tasks): task.cancel() self._background_tasks.clear() # Clear track maps self.track_map.clear() self.video_frame_trackers.clear() await super().close() self._closed = True🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@getstream/video/rtc/pc.py` around lines 258 - 281, The close() method must ensure super().close() and self._closed = True run even if cleanup steps raise; wrap the cleanup of self._video_drains and cancellation of self._background_tasks in a try/except/finally (or try/finally) so exceptions from await blackhole.stop() (or drain_task.cancel()/drain_proxy.stop()) are caught/logged and do not prevent calling await super().close() and setting self._closed; locate the close method and apply the change around the blocks using self._video_drains, self._background_tasks, and the call to super().close() so cleanup errors are handled but the underlying RTCPeerConnection is always closed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@getstream/video/rtc/pc.py`:
- Around line 258-281: The close() method must ensure super().close() and
self._closed = True run even if cleanup steps raise; wrap the cleanup of
self._video_drains and cancellation of self._background_tasks in a
try/except/finally (or try/finally) so exceptions from await blackhole.stop()
(or drain_task.cancel()/drain_proxy.stop()) are caught/logged and do not prevent
calling await super().close() and setting self._closed; locate the close method
and apply the change around the blocks using self._video_drains,
self._background_tasks, and the call to super().close() so cleanup errors are
handled but the underlying RTCPeerConnection is always closed.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 975e6331-f4ae-4672-9bde-699c7aa2e190
📒 Files selected for processing (4)
getstream/video/rtc/pc.pygetstream/video/rtc/reconnection.pytests/rtc/test_connection_manager.pytests/rtc/test_subscriber_drain.py
Previously, the repeated close() calls were hanging indefinitely for PublisherPeerConnection and SubscriberPeerConnection.
Now, we set
_closed=Trueguard when* the connection is closed for the first time and exit early on the repeated call.Summary by CodeRabbit
Bug Fixes
Tests
Chores