fix: memory leak hunting and reconnecting on data error

This commit is contained in:
2026-05-18 19:37:30 +02:00
parent dea114aed0
commit 0152ed9dd2
5 changed files with 148 additions and 60 deletions

View File

@@ -154,6 +154,18 @@ export function scheduleDataChannelRecovery(
if (channel.readyState === DATA_CHANNEL_STATE_OPEN)
return;
if (channel.readyState === 'closed') {
logger.warn('[data-channel] Control channel closed; reconnecting peer immediately', {
channelLabel: channel.label,
connectionState: peerData.connection.connectionState,
peerId,
reason
});
repairUnavailableDataChannel(context, peerId, channel, reason, handlers);
return;
}
if (state.dataChannelRecoveryTimers.has(peerId))
return;
@@ -183,35 +195,42 @@ export function scheduleDataChannelRecovery(
reason
});
if (latestPeerData.connection.connectionState === CONNECTION_STATE_CONNECTED) {
if (latestPeerData.isInitiator && handlers.replaceDataChannel(peerId, channel)) {
logger.info('[data-channel] Replaced control channel without recreating media transport', {
peerId,
reason
});
return;
}
if (!latestPeerData.isInitiator) {
logger.info('[data-channel] Waiting for initiator to replace control channel; preserving media transport', {
peerId,
reason
});
return;
}
}
trackDisconnectedPeer(state, peerId);
handlers.removePeer(peerId, { preserveReconnectState: true });
attemptPeerReconnect(context, peerId, handlers);
schedulePeerReconnect(context, peerId, handlers);
repairUnavailableDataChannel(context, peerId, channel, reason, handlers);
}, DATA_CHANNEL_RECOVERY_GRACE_MS);
state.dataChannelRecoveryTimers.set(peerId, timer);
}
function repairUnavailableDataChannel(
context: PeerConnectionManagerContext,
peerId: string,
channel: RTCDataChannel,
reason: string,
handlers: RecoveryHandlers
): void {
const { logger, state } = context;
const peerData = state.activePeerConnections.get(peerId);
if (!peerData || peerData.dataChannel !== channel)
return;
if (peerData.dataChannel?.readyState === DATA_CHANNEL_STATE_OPEN)
return;
logger.warn('[data-channel] Recreating peer transport after control channel failure', {
channelLabel: channel.label,
connectionState: peerData.connection.connectionState,
peerId,
readyState: peerData.dataChannel?.readyState ?? null,
reason
});
trackDisconnectedPeer(state, peerId);
handlers.removePeer(peerId, { preserveReconnectState: true });
attemptPeerReconnect(context, peerId, handlers);
schedulePeerReconnect(context, peerId, handlers);
}
export function schedulePeerDisconnectRecovery(
context: PeerConnectionManagerContext,
peerId: string,