fix: 修复channelInactive状态检查不完整导致的重连问题
- 将 channelInactive 的状态检查从仅处理 connected 状态改为处理所有非 closed/disconnected 状态 - 与 errorCaught 的处理逻辑保持一致 - 确保在 connecting/pending 状态下网络断开时也能正确触发重连
This commit is contained in:
@@ -901,7 +901,7 @@ class ConnectionHandler: ChannelInboundHandler {
|
|||||||
continuation.resume(throwing: errorToUse)
|
continuation.resume(throwing: errorToUse)
|
||||||
}
|
}
|
||||||
|
|
||||||
let shouldHandleDisconnect = state.withLockedValue { $0 == .connected }
|
let shouldHandleDisconnect = state.withLockedValue { $0 != .closed && $0 != .disconnected }
|
||||||
if shouldHandleDisconnect {
|
if shouldHandleDisconnect {
|
||||||
handleDisconnect()
|
handleDisconnect()
|
||||||
}
|
}
|
||||||
@@ -923,16 +923,44 @@ class ConnectionHandler: ChannelInboundHandler {
|
|||||||
} else {
|
} else {
|
||||||
logger.error("unexpected error: \(error)")
|
logger.error("unexpected error: \(error)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unified handling: use handleDisconnect for all non-closed/non-disconnected states
|
||||||
let currentState = state.withLockedValue { $0 }
|
let currentState = state.withLockedValue { $0 }
|
||||||
if currentState == .pending || currentState == .connecting {
|
if currentState != .closed && currentState != .disconnected {
|
||||||
handleDisconnect()
|
handleDisconnect()
|
||||||
} else if currentState == .disconnected {
|
|
||||||
handleReconnect()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleDisconnect() {
|
func handleDisconnect() {
|
||||||
state.withLockedValue { $0 = .disconnected }
|
// Prevent duplicate disconnect handling
|
||||||
|
let shouldProceed = state.withLockedValue { currentState -> Bool in
|
||||||
|
if currentState == .disconnected || currentState == .closed {
|
||||||
|
return false // Already in disconnected/closed state
|
||||||
|
}
|
||||||
|
$0 = .disconnected
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
guard shouldProceed else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up pending continuations to prevent leaks
|
||||||
|
if let continuation = serverInfoContinuation.withLockedValue({ cont in
|
||||||
|
let toResume = cont
|
||||||
|
cont = nil
|
||||||
|
return toResume
|
||||||
|
}) {
|
||||||
|
continuation.resume(throwing: NatsError.ClientError.connectionClosed)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let continuation = connectionEstablishedContinuation.withLockedValue({ cont in
|
||||||
|
let toResume = cont
|
||||||
|
cont = nil
|
||||||
|
return toResume
|
||||||
|
}) {
|
||||||
|
continuation.resume(throwing: NatsError.ClientError.connectionClosed)
|
||||||
|
}
|
||||||
|
|
||||||
// Safely clear batchBuffer first to avoid race conditions
|
// Safely clear batchBuffer first to avoid race conditions
|
||||||
let bufferToRelease = self.batchBuffer
|
let bufferToRelease = self.batchBuffer
|
||||||
@@ -963,12 +991,17 @@ class ConnectionHandler: ChannelInboundHandler {
|
|||||||
self.handleReconnect()
|
self.handleReconnect()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No channel, start reconnect immediately
|
self.fire(.disconnected)
|
||||||
handleReconnect()
|
handleReconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleReconnect() {
|
func handleReconnect() {
|
||||||
|
// Cancel any existing reconnect task to prevent multiple concurrent reconnections
|
||||||
|
if let oldTask = reconnectTask {
|
||||||
|
oldTask.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
reconnectTask = Task {
|
reconnectTask = Task {
|
||||||
var connected = false
|
var connected = false
|
||||||
while !Task.isCancelled
|
while !Task.isCancelled
|
||||||
@@ -984,7 +1017,7 @@ class ConnectionHandler: ChannelInboundHandler {
|
|||||||
} catch {
|
} catch {
|
||||||
logger.debug("Could not reconnect: \(error)")
|
logger.debug("Could not reconnect: \(error)")
|
||||||
if !Task.isCancelled {
|
if !Task.isCancelled {
|
||||||
try await Task.sleep(nanoseconds: self.reconnectWait)
|
try? await Task.sleep(nanoseconds: self.reconnectWait)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -998,7 +1031,7 @@ class ConnectionHandler: ChannelInboundHandler {
|
|||||||
// If we got here without connecting and weren't cancelled, we hit max reconnects
|
// If we got here without connecting and weren't cancelled, we hit max reconnects
|
||||||
if !connected {
|
if !connected {
|
||||||
logger.error("Could not reconnect; maxReconnects exceeded")
|
logger.error("Could not reconnect; maxReconnects exceeded")
|
||||||
try await self.close()
|
try? await self.close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user