fix: harden websocket heartbeat under load

This commit is contained in:
richjohnrambo
2026-09-30 17:36:33 +08:00
parent b83800c0f3
commit 2b631ab176
12 changed files with 228 additions and 9 deletions
+28 -6
View File
@@ -28,14 +28,35 @@ import (
const (
// Time allowed to write a message to the peer.
writeWait = 10 * time.Second
// Time allowed to read the next pong message from the peer.
pongWait = idleSessionTimeout
// Send pings to peer with this period. Must be less than pongWait.
pingPeriod = 15 * time.Second
// Heartbeat defaults tolerate transient mobile and public-network stalls while
// still detecting dead connections in a bounded amount of time.
defaultWSPongWait = 90 * time.Second
defaultWSPingPeriod = 15 * time.Second
)
var (
pongWait = defaultWSPongWait
pingPeriod = defaultWSPingPeriod
)
func configureWSHeartbeat(pingSeconds, pongSeconds int) error {
ping := defaultWSPingPeriod
pong := defaultWSPongWait
if pingSeconds > 0 {
ping = time.Duration(pingSeconds) * time.Second
}
if pongSeconds > 0 {
pong = time.Duration(pongSeconds) * time.Second
}
if ping >= pong {
return errors.New("websocket ping period must be shorter than pong wait")
}
pingPeriod = ping
pongWait = pong
immetrics.SetWSHeartbeatConfig(ping, pong)
return nil
}
func (sess *Session) closeWS() {
if sess.proto == WEBSOCK {
sess.ws.Close()
@@ -52,6 +73,7 @@ func (sess *Session) readLoop() {
sess.ws.SetReadDeadline(time.Now().Add(pongWait))
sess.ws.SetPongHandler(func(string) error {
atomic.StoreInt64(&sess.lastAction, types.TimeNow().UnixNano())
immetrics.IncWSHeartbeat("pong_received")
sess.refreshPresence("ws.pong")
sess.ws.SetReadDeadline(time.Now().Add(pongWait))
return nil