fix: cancel in-flight connect on disconnect to prevent second-attempt bug#182
Open
staging-devin-ai-integration[bot] wants to merge 3 commits intodevin/1774202776-declarative-client-sectionfrom
Conversation
… bug The core issue: disconnect() during an in-flight performConnect() could not cancel it. The local 'attempt' objects (Camera, Connection, etc.) lived in performConnect's stack frame and were never cleaned up by disconnect()'s cleanupConnectAttempt() call (which only saw the store's null refs). When the user started a new pipeline, performConnect₁ would eventually complete and overwrite the store — clobbering performConnect₂'s state, leaking resources, or flipping the UI back to 'disconnected'. Changes: - Add AbortController to stream store; abort on disconnect() and connect() - Thread AbortSignal through waitForSignalValue, waitForBroadcastAnnouncement, setupMediaSources, setupPublishPath, and performConnect - Aborted performConnect silently discards its attempt (no store writes) - Add connectingStep state for granular UX feedback during connect phases (devices → relay → pipeline) - Surface auto-connect errors in StreamView instead of silently logging - Extract createConnectionAndHealth() and connectWatchPath() helpers to keep performConnect under the max-statements lint threshold - Add tests for abort signal cancellation in waitForSignalValue and disconnect-during-connect in streamStore Co-Authored-By: Claudio Costa <cstcld91@gmail.com>
Co-Authored-By: Claudio Costa <cstcld91@gmail.com>
Contributor
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
…ort in waitForBroadcastAnnouncement - Add connectAbort and connectingStep to the beforeEach setState reset to prevent test pollution across runs. - Replace polling abort check in waitForBroadcastAnnouncement with an event-driven abortPromise in Promise.race so abort fires immediately even when announcements.next() is blocked. Co-Authored-By: Claudio Costa <cstcld91@gmail.com>
Contributor
Author
E2E Test Results — Connect Lifecycle FixesRan Puppeteer headless Chrome ( Test Results (5/5 passed)
Status progression captured by MutationObserver (TC1)Caveats
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a race condition where
disconnect()during an in-flightperformConnect()could not cancel it, causing the "start a pipeline → destroy → start a new one" flow to break reliably.Root cause:
performConnect()creates MoQ resources (Camera, Connection, etc.) in local variables that aren't stored in the Zustand store until the final successset(). Whendisconnect()runs mid-connect,cleanupConnectAttempt()only sees null refs in the store — the in-flight objects are never cleaned up. The staleperformConnect₁then overwrites the store when it eventually completes or times out, clobberingperformConnect₂'s state.Fix: Add an
AbortControllerto the store.disconnect()andconnect()abort any in-flight attempt.AbortSignalis threaded through every async wait (waitForSignalValue,waitForBroadcastAnnouncement,setupMediaSources,setupPublishPath). An abortedperformConnectcleans up its local resources and silently returns without writing to the store.UX improvements:
connectingStepstate ('devices'→'relay'→'pipeline') shown during the connecting phase so users see what's happening instead of a generic "Connecting…"Refactors:
createConnectionAndHealth()andconnectWatchPath()helpers fromperformConnectto stay under themax-statementslint thresholdReview & Testing Checklist for Human
Notes
AbortSignalintegration usesDOMException('Aborted', 'AbortError')which is the standard Web API pattern.Link to Devin session: https://staging.itsdev.in/sessions/8352254860d447efb51e249658d0eaf0
Requested by: @streamer45