fix(notify): 根治低带宽控制面阻塞与传输写入卡死

- 为控制消息增加优先级、公平调度、队列字节预算和自适应批处理
- 支持可取消的写门等待,收紧 shared/dedicated bulk、stream 和 Reply 写入边界
- 修复 bulk reset/close、连接 handoff 和安全 profile 切换时序
- 保留旧取消与超时错误契约,新增阶段化 TransportSendError
- 增加 ReplyCtx、ReplyObjCtx、写超时配置及黑洞连接和竞态回归测试
This commit is contained in:
2026-08-14 10:16:37 +08:00
parent 98ef9e7fcc
commit 0826e17063
45 changed files with 4231 additions and 293 deletions
+61 -20
View File
@@ -1,10 +1,13 @@
package notify
import (
"context"
"net"
"time"
)
const defaultMessageReplyWriteTimeout = 30 * time.Second
const (
MSG_SYS MessageType = iota
MSG_SYS_WAIT
@@ -55,16 +58,40 @@ type WaitMsg struct {
}
type messageLogicalTransferSender interface {
sendLogical(*LogicalConn, TransferMsg) (WaitMsg, error)
sendLogicalContext(context.Context, *LogicalConn, TransferMsg, time.Duration) (WaitMsg, error)
}
type messageTransportTransferSender interface {
sendTransportContextWithWriteTimeout(context.Context, *TransportConn, TransferMsg, time.Duration) (WaitMsg, error)
}
type messageInboundTransferSender interface {
sendTransferInbound(*LogicalConn, *TransportConn, net.Conn, *transportProtectionProfile, TransferMsg) error
sendTransferInboundContext(context.Context, *LogicalConn, *TransportConn, net.Conn, *transportProtectionProfile, TransferMsg, time.Duration) error
}
type messageClientTransferSender interface {
sendWithContextTimeout(context.Context, TransferMsg, time.Duration) (WaitMsg, error)
}
type messageReplyWriteTimeoutProvider interface {
ReplyWriteTimeout() time.Duration
}
func (m *Message) Reply(value MsgVal) (err error) {
return m.replyContext(context.Background(), value)
}
func (m *Message) ReplyCtx(ctx context.Context, value MsgVal) (err error) {
if ctx == nil {
ctx = context.Background()
}
return m.replyContext(ctx, value)
}
func (m *Message) replyContext(ctx context.Context, value MsgVal) (err error) {
logical := messageLogicalConnSnapshot(m)
transport := messageTransportConnSnapshot(m)
writeTimeout := defaultMessageReplyWriteTimeout
reply := TransferMsg{
ID: m.ID,
Key: m.Key,
@@ -78,21 +105,6 @@ func (m *Message) Reply(value MsgVal) (err error) {
reply.Type = MSG_SYS_REPLY
}
if m.NetType == NET_SERVER {
if m.inboundConn != nil && logical != nil {
server := logical.Server()
if server == nil {
return transportDetachedErrorForPeer(logical, transport)
}
sender, _ := server.(messageInboundTransferSender)
if sender == nil {
return transportDetachedErrorForPeer(logical, transport)
}
return sender.sendTransferInbound(logical, transport, m.inboundConn, messageInboundTransportProtectionSnapshot(m), reply)
}
if transport != nil {
_, err = transport.sendTransfer(reply)
return
}
if logical == nil {
return transportDetachedErrorForPeer(nil, transport)
}
@@ -100,24 +112,53 @@ func (m *Message) Reply(value MsgVal) (err error) {
if server == nil {
return transportDetachedErrorForPeer(logical, transport)
}
if provider, ok := server.(messageReplyWriteTimeoutProvider); ok {
writeTimeout = provider.ReplyWriteTimeout()
}
if m.inboundConn != nil && logical != nil {
sender, _ := server.(messageInboundTransferSender)
if sender == nil {
return transportDetachedErrorForPeer(logical, transport)
}
return sender.sendTransferInboundContext(ctx, logical, transport, m.inboundConn, messageInboundTransportProtectionSnapshot(m), reply, writeTimeout)
}
if transport != nil {
sender, _ := server.(messageTransportTransferSender)
if sender == nil {
return transportDetachedErrorForPeer(logical, transport)
}
_, err = sender.sendTransportContextWithWriteTimeout(ctx, transport, reply, writeTimeout)
return err
}
sender, _ := server.(messageLogicalTransferSender)
if sender == nil {
return transportDetachedErrorForPeer(logical, transport)
}
_, err = sender.sendLogical(logical, reply)
_, err = sender.sendLogicalContext(ctx, logical, reply, writeTimeout)
}
if m.NetType == NET_CLIENT {
_, err = m.ServerConn.send(reply)
if m.ServerConn == nil {
return net.ErrClosed
}
if sender, ok := m.ServerConn.(messageClientTransferSender); ok {
_, err = sender.sendWithContextTimeout(ctx, reply, writeTimeout)
} else {
_, err = m.ServerConn.send(reply)
}
}
return
}
func (m *Message) ReplyObj(value interface{}) (err error) {
return m.ReplyObjCtx(context.Background(), value)
}
func (m *Message) ReplyObjCtx(ctx context.Context, value interface{}) (err error) {
data, err := encode(value)
if err != nil {
return err
}
return m.Reply(data)
return m.ReplyCtx(ctx, data)
}
func hydrateServerMessagePeerFields(message Message) Message {