concept-collection / commonview
p2p: retry stalled connection attempts
Signaling events are ephemeral, so an offer published before the other peer was listening is lost, and maybeConnect skipped any peer that already had a (dead, never-opened) connection entry -- deadlocking the pair forever. Tear down attempts that haven't opened after 15s and re-initiate on the peer's next announcement.
Jeremy Magland <jmagland@flatironinstitute.org> committed commit 526393677839 parent a5fdddc Browse files
1 changed file+19−2
src/p2p/network.tsmodified+19−2View file
@@ -65,9 +65,16 @@ export interface Snapshot {
6565
6666 const ANNOUNCE_INTERVAL_MS = 5000
6767 const ROOM_ID = 'default'
68+// A connection attempt that hasn't opened after this long is torn down and
69+// retried on the peer's next announcement. Signaling events are ephemeral, so
70+// an offer published before the other side was listening is simply lost —
71+// without a retry the pair would deadlock forever.
72+const CONNECT_RETRY_MS = 15000
6873
6974 interface Connection {
7075 peer: Peer
76+ /** When this connection attempt started (local clock), for retry pacing. */
77+ createdAt: number
7178 connectedAt: number | null // self-reported timestamp from the remote peer
7279 }
7380
@@ -132,7 +139,17 @@ export class Network {
132139 // ---- connection setup -------------------------------------------------
133140
134141 private maybeConnect(peerId: string) {
135- if (peerId === selfId || this.connections.has(peerId)) return
142+ if (peerId === selfId) return
143+ const existing = this.connections.get(peerId)
144+ if (existing) {
145+ const stalled =
146+ !existing.peer.isConnected &&
147+ Date.now() - existing.createdAt > CONNECT_RETRY_MS
148+ if (!stalled) return
149+ // destroy() fires the close handler, which removes it from the map.
150+ existing.peer.destroy()
151+ this.connections.delete(peerId)
152+ }
136153 // Deterministic initiator: the peer with the smaller ID makes the offer.
137154 const initiator = selfId < peerId
138155 this.createPeer(peerId, initiator)
@@ -140,7 +157,7 @@ export class Network {
140157
141158 private createPeer(peerId: string, initiator: boolean): Connection {
142159 const peer = new Peer(initiator)
143- const conn: Connection = {peer, connectedAt: null}
160+ const conn: Connection = {peer, createdAt: Date.now(), connectedAt: null}
144161 this.connections.set(peerId, conn)
145162
146163 peer.setHandlers({