55 "encoding/json"
66 "errors"
77 "fmt"
8+ "log"
89 "net"
910 "strings"
1011 "sync"
@@ -17,10 +18,11 @@ import (
1718)
1819
1920const (
20- defaultGatewayRPCRequestTimeout = 8 * time .Second
21- defaultGatewayRPCRetryCount = 1
22- defaultGatewayNotificationBuffer = 64
23- defaultGatewayNotificationQueue = 256
21+ defaultGatewayRPCRequestTimeout = 8 * time .Second
22+ defaultGatewayRPCRetryCount = 1
23+ defaultGatewayNotificationBuffer = 64
24+ defaultGatewayNotificationQueue = 256
25+ defaultGatewayNotificationEnqueueTimeout = 3 * time .Second
2426)
2527
2628// GatewayRPCClientOptions 描述网关 JSON-RPC 客户端的初始化参数。
@@ -107,11 +109,12 @@ type GatewayRPCClient struct {
107109 conn net.Conn
108110 pending map [string ]chan gatewayRPCResponse
109111
110- notifications chan gatewayRPCNotification
111- notificationQueue chan gatewayRPCNotification
112- notificationWG sync.WaitGroup
113- notificationStart sync.Once
114- sequence uint64
112+ notifications chan gatewayRPCNotification
113+ notificationQueue chan gatewayRPCNotification
114+ notificationEnqueueTimeout time.Duration
115+ notificationWG sync.WaitGroup
116+ notificationStart sync.Once
117+ sequence uint64
115118}
116119
117120// NewGatewayRPCClient 创建网关 RPC 客户端,并在启动时静默读取认证 Token。
@@ -146,15 +149,16 @@ func NewGatewayRPCClient(options GatewayRPCClientOptions) (*GatewayRPCClient, er
146149 }
147150
148151 return & GatewayRPCClient {
149- listenAddress : listenAddress ,
150- token : token ,
151- requestTimeout : requestTimeout ,
152- retryCount : retryCount ,
153- dialFn : dialFn ,
154- closed : make (chan struct {}),
155- pending : make (map [string ]chan gatewayRPCResponse ),
156- notifications : make (chan gatewayRPCNotification , defaultGatewayNotificationBuffer ),
157- notificationQueue : make (chan gatewayRPCNotification , defaultGatewayNotificationQueue ),
152+ listenAddress : listenAddress ,
153+ token : token ,
154+ requestTimeout : requestTimeout ,
155+ retryCount : retryCount ,
156+ dialFn : dialFn ,
157+ closed : make (chan struct {}),
158+ pending : make (map [string ]chan gatewayRPCResponse ),
159+ notifications : make (chan gatewayRPCNotification , defaultGatewayNotificationBuffer ),
160+ notificationQueue : make (chan gatewayRPCNotification , defaultGatewayNotificationQueue ),
161+ notificationEnqueueTimeout : defaultGatewayNotificationEnqueueTimeout ,
158162 }, nil
159163}
160164
@@ -232,7 +236,6 @@ func (c *GatewayRPCClient) Close() error {
232236 c .closeOnce .Do (func () {
233237 close (c .closed )
234238 firstErr = c .forceCloseWithError (errors .New ("gateway rpc client closed" ))
235- close (c .notificationQueue )
236239 c .notificationWG .Wait ()
237240 close (c .notifications )
238241 })
@@ -372,7 +375,9 @@ func (c *GatewayRPCClient) readLoop(conn net.Conn) {
372375 if paramsRaw , hasParams := envelope ["params" ]; hasParams {
373376 notification .Params = cloneJSONRawMessage (paramsRaw )
374377 }
375- c .enqueueNotification (notification )
378+ if ! c .enqueueNotification (notification ) {
379+ return
380+ }
376381 continue
377382 }
378383
@@ -387,7 +392,7 @@ func (c *GatewayRPCClient) readLoop(conn net.Conn) {
387392 }
388393}
389394
390- // startNotificationDispatcher 启动通知转发协程,确保 readLoop 不会被 UI 消费速度阻塞 。
395+ // startNotificationDispatcher 启动通知转发协程,配合 enqueue 超时保护避免 readLoop 长时间背压阻塞 。
391396func (c * GatewayRPCClient ) startNotificationDispatcher () {
392397 c .notificationStart .Do (func () {
393398 c .notificationWG .Add (1 )
@@ -412,12 +417,25 @@ func (c *GatewayRPCClient) startNotificationDispatcher() {
412417 })
413418}
414419
415- // enqueueNotification 以阻塞方式投递通知,确保 gateway.event 不会因队列满被静默丢弃。
416- func (c * GatewayRPCClient ) enqueueNotification (notification gatewayRPCNotification ) {
420+ // enqueueNotification 投递通知到内部队列;若背压持续超时则主动断开连接,避免 readLoop 无限阻塞。
421+ func (c * GatewayRPCClient ) enqueueNotification (notification gatewayRPCNotification ) bool {
422+ enqueueTimeout := c .notificationEnqueueTimeout
423+ if enqueueTimeout <= 0 {
424+ enqueueTimeout = defaultGatewayNotificationEnqueueTimeout
425+ }
426+ timer := time .NewTimer (enqueueTimeout )
427+ defer timer .Stop ()
428+
417429 select {
418430 case <- c .closed :
419- return
431+ return false
420432 case c .notificationQueue <- notification :
433+ return true
434+ case <- timer .C :
435+ err := fmt .Errorf ("gateway rpc client: notification queue blocked for %s" , enqueueTimeout )
436+ log .Printf ("warning: gateway rpc client force close due to notification backpressure method=%s err=%v" , notification .Method , err )
437+ _ = c .forceCloseWithError (err )
438+ return false
421439 }
422440}
423441
0 commit comments