@@ -490,34 +490,62 @@ func (s *Service) updateEndpointTunnelCount(endpointID int64) {
490490// sendTunnelUpdateByInstanceId 根据实例ID发送隧道更新
491491func (s * Service ) sendTunnelUpdateByInstanceId (instanceID string , data SSEResp ) {
492492 s .mu .RLock ()
493- defer s .mu .RUnlock ()
494-
495493 subscribers , exists := s .tunnelSubs [instanceID ]
496494 if ! exists {
495+ s .mu .RUnlock ()
497496 // log.Debug("[SSE]隧道 %s 没有订阅者", instanceID)
498497 return
499498 }
500499
500+ // 创建订阅者副本,避免在遍历时修改map
501+ clientList := make ([]* Client , 0 , len (subscribers ))
502+ clientIDs := make ([]string , 0 , len (subscribers ))
503+ for clientID , client := range subscribers {
504+ clientList = append (clientList , client )
505+ clientIDs = append (clientIDs , clientID )
506+ }
507+ s .mu .RUnlock ()
508+
501509 jsonData , err := json .Marshal (data )
502510 if err != nil {
503511 log .Errorf ("序列化隧道数据失败: %v" , err )
504512 return
505513 }
506514
507- for clientID , client := range subscribers {
515+ // 记录需要删除的客户端
516+ disconnectedClients := make ([]string , 0 )
517+
518+ for i , client := range clientList {
519+ clientID := clientIDs [i ]
508520 if err := client .Send (jsonData ); err != nil {
509521 // 检查是否是连接断开错误,使用更合适的日志级别
510522 if client .IsDisconnected () {
511- log .Warnf ("[SSE]客户端 %s 连接已断开,移除订阅" , clientID )
512- // 从订阅列表中移除已断开的客户端
513- delete (subscribers , clientID )
523+ log .Warnf ("[SSE]客户端 %s 连接已断开,标记移除订阅" , clientID )
524+ disconnectedClients = append (disconnectedClients , clientID )
514525 } else {
515526 log .Errorf ("发送隧道更新给客户端 %s 失败: %v" , clientID , err )
516527 }
517528 } else {
518529 log .Debugf ("[SSE]隧道 %s 的订阅者 %s 推送成功" , instanceID , clientID )
519530 }
520531 }
532+
533+ // 如果有断开的客户端,获取写锁并移除它们
534+ if len (disconnectedClients ) > 0 {
535+ s .mu .Lock ()
536+ if subscribers , exists := s .tunnelSubs [instanceID ]; exists {
537+ for _ , clientID := range disconnectedClients {
538+ delete (subscribers , clientID )
539+ log .Infof ("[SSE]已移除断开连接的客户端 %s from tunnel %s" , clientID , instanceID )
540+ }
541+ // 如果订阅者列表为空,删除整个条目
542+ if len (subscribers ) == 0 {
543+ delete (s .tunnelSubs , instanceID )
544+ log .Debugf ("[SSE]隧道 %s 无订阅者,清理订阅列表" , instanceID )
545+ }
546+ }
547+ s .mu .Unlock ()
548+ }
521549}
522550
523551// setTunnelsOfflineForEndpoint 将端点的所有隧道设置为离线状态
0 commit comments