@@ -10,8 +10,8 @@ import (
10
10
"time"
11
11
12
12
"github.com/0xJacky/Nginx-UI/internal/analytic"
13
- "github.com/0xJacky/Nginx-UI/internal/kernel"
14
13
"github.com/0xJacky/Nginx-UI/internal/helper"
14
+ "github.com/0xJacky/Nginx-UI/internal/kernel"
15
15
"github.com/0xJacky/Nginx-UI/model"
16
16
"github.com/gin-gonic/gin"
17
17
"github.com/gorilla/websocket"
@@ -51,7 +51,7 @@ func GetHub() *Hub {
51
51
hubOnce .Do (func () {
52
52
hub = & Hub {
53
53
clients : make (map [* Client ]bool ),
54
- broadcast : make (chan WebSocketMessage , 256 ),
54
+ broadcast : make (chan WebSocketMessage , 1024 ), // Increased buffer size
55
55
register : make (chan * Client ),
56
56
unregister : make (chan * Client ),
57
57
}
@@ -81,15 +81,35 @@ func (h *Hub) run() {
81
81
82
82
case message := <- h .broadcast :
83
83
h .mutex .RLock ()
84
+ deadClients := make ([]* Client , 0 )
84
85
for client := range h .clients {
85
86
select {
86
87
case client .send <- message :
88
+ case <- time .After (100 * time .Millisecond ):
89
+ // Client is too slow, mark for removal
90
+ logger .Debug ("Client send channel timeout, marking for removal" )
91
+ deadClients = append (deadClients , client )
87
92
default :
88
- close (client .send )
89
- delete (h .clients , client )
93
+ // Channel is full, mark for removal
94
+ logger .Debug ("Client send channel full, marking for removal" )
95
+ deadClients = append (deadClients , client )
90
96
}
91
97
}
92
98
h .mutex .RUnlock ()
99
+
100
+ // Clean up dead clients
101
+ if len (deadClients ) > 0 {
102
+ h .mutex .Lock ()
103
+ for _ , client := range deadClients {
104
+ if _ , ok := h .clients [client ]; ok {
105
+ close (client .send )
106
+ delete (h .clients , client )
107
+ client .cancel () // Trigger client cleanup
108
+ }
109
+ }
110
+ h .mutex .Unlock ()
111
+ logger .Info ("Cleaned up slow/unresponsive clients" , "count" , len (deadClients ))
112
+ }
93
113
}
94
114
}
95
115
}
@@ -135,7 +155,7 @@ func GetAllEnabledEnvironmentWS(c *gin.Context) {
135
155
136
156
client := & Client {
137
157
conn : ws ,
138
- send : make (chan WebSocketMessage , 256 ),
158
+ send : make (chan WebSocketMessage , 1024 ), // Increased buffer size
139
159
ctx : ctx ,
140
160
cancel : cancel ,
141
161
}
@@ -222,7 +242,7 @@ func (c *Client) handleEnvironmentMonitoring() {
222
242
}
223
243
}
224
244
225
- // sendMessage sends a message to the client
245
+ // sendMessage sends a message to the client with timeout and better error handling
226
246
func (c * Client ) sendMessage (event string , data any ) {
227
247
message := WebSocketMessage {
228
248
Event : event ,
@@ -231,8 +251,16 @@ func (c *Client) sendMessage(event string, data any) {
231
251
232
252
select {
233
253
case c .send <- message :
254
+ case <- time .After (5 * time .Second ):
255
+ logger .Warn ("Client send channel full, message dropped after timeout" , "event" , event )
256
+ // Force disconnect slow clients to prevent resource leakage
257
+ c .cancel ()
234
258
default :
235
- logger .Warn ("Client send channel full, message dropped" )
259
+ logger .Warn ("Client send channel full, message dropped immediately" , "event" , event )
260
+ // For non-critical messages, we can drop them immediately
261
+ if event != "heartbeat" {
262
+ logger .Info ("Dropping non-critical message due to full channel" , "event" , event )
263
+ }
236
264
}
237
265
}
238
266
@@ -290,7 +318,7 @@ func (c *Client) readPump() {
290
318
if helper .IsUnexpectedWebsocketError (err ) {
291
319
logger .Error ("Websocket error:" , err )
292
320
}
293
- return
321
+ return
294
322
}
295
323
}
296
324
}()
0 commit comments