Add websocket_idle_timeout_seconds
config for idle WebSocket cleanup (#21493)
This commit is contained in:
parent
36d14eddc8
commit
1cda716da5
@ -40,6 +40,9 @@ func main() {
|
||||
log.Infof("Json Patch Disabled!")
|
||||
}
|
||||
|
||||
// Routine to check for idle connections and close them
|
||||
go websrv.InvalidateIdleBrowserConnectionsRoutine()
|
||||
|
||||
// Websocket listener
|
||||
|
||||
rateLimiter := common.NewCustomRateLimiter(cfg.Server.MaxConnectionsPerSecond)
|
||||
|
@ -29,6 +29,7 @@ type Config struct {
|
||||
JsonPatchDisabled bool `yaml:"json_patch_disabled"`
|
||||
SubscriptionAllowedList string `yaml:"subscriptions_allowed_list"`
|
||||
SubscriptionsDeniedList string `yaml:"subscriptions_denied_list"`
|
||||
WebsocketIdleTimeoutSeconds int `yaml:"websocket_idle_timeout_seconds"`
|
||||
} `yaml:"server"`
|
||||
Redis struct {
|
||||
Host string `yaml:"host"`
|
||||
|
@ -12,6 +12,7 @@ server:
|
||||
json_patch_disabled: false
|
||||
subscriptions_allowed_list:
|
||||
subscriptions_denied_list:
|
||||
websocket_idle_timeout_seconds: 60
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"nhooyr.io/websocket"
|
||||
)
|
||||
@ -56,6 +57,8 @@ type BrowserConnection struct {
|
||||
FromBrowserToHasuraChannel *SafeChannelByte // channel to transmit messages from Browser to Hasura
|
||||
FromBrowserToGqlActionsChannel *SafeChannelByte // channel to transmit messages from Browser to Graphq-Actions
|
||||
FromHasuraToBrowserChannel *SafeChannelByte // channel to transmit messages from Hasura/GqlActions to Browser
|
||||
LastBrowserMessageTime time.Time // stores the time of the last message to control browser idleness
|
||||
LastBrowserMessageTimeMutex sync.RWMutex // mutex for LastBrowserMessageTime
|
||||
Logger *logrus.Entry // connection logger populated with connection info
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,7 @@ func HasuraClient(
|
||||
defer func() {
|
||||
//When Hasura sends an CloseError, it will forward the error to the browser and close the connection
|
||||
if thisConnection.WebsocketCloseError != nil {
|
||||
browserConnection.Logger.Infof("Closing browser connection because Hasura connection was closed, reason: %s", thisConnection.WebsocketCloseError.Reason)
|
||||
browserConnection.Websocket.Close(thisConnection.WebsocketCloseError.Code, thisConnection.WebsocketCloseError.Reason)
|
||||
browserConnection.ContextCancelFunc()
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ func ConnectionHandler(w http.ResponseWriter, r *http.Request) {
|
||||
FromBrowserToHasuraChannel: common.NewSafeChannelByte(bufferSize),
|
||||
FromBrowserToGqlActionsChannel: common.NewSafeChannelByte(bufferSize),
|
||||
FromHasuraToBrowserChannel: common.NewSafeChannelByte(bufferSize),
|
||||
LastBrowserMessageTime: time.Now(),
|
||||
Logger: connectionLogger,
|
||||
}
|
||||
|
||||
@ -494,3 +495,27 @@ func disconnectWithError(
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var websocketIdleTimeoutSeconds = config.GetConfig().Server.WebsocketIdleTimeoutSeconds
|
||||
|
||||
func InvalidateIdleBrowserConnectionsRoutine() {
|
||||
for {
|
||||
time.Sleep(15 * time.Second)
|
||||
|
||||
BrowserConnectionsMutex.RLock()
|
||||
for _, browserConnection := range BrowserConnections {
|
||||
browserConnection.LastBrowserMessageTimeMutex.RLock()
|
||||
browserIdleSince := time.Since(browserConnection.LastBrowserMessageTime)
|
||||
browserConnection.LastBrowserMessageTimeMutex.RUnlock()
|
||||
|
||||
if browserIdleSince > time.Duration(websocketIdleTimeoutSeconds)*time.Second {
|
||||
browserConnection.Logger.Info("Closing browser connection, reason: idle timeout")
|
||||
errCloseWs := browserConnection.Websocket.Close(websocket.StatusNormalClosure, "idle timeout")
|
||||
if errCloseWs != nil {
|
||||
browserConnection.Logger.Debugf("Error on close websocket: %v", errCloseWs)
|
||||
}
|
||||
}
|
||||
}
|
||||
BrowserConnectionsMutex.RUnlock()
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ func BrowserConnectionReader(
|
||||
|
||||
for {
|
||||
messageType, message, err := browserConnection.Websocket.Read(browserConnection.Context)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
browserConnection.Logger.Debugf("Closing Browser ws connection as Context was cancelled!")
|
||||
@ -45,6 +46,9 @@ func BrowserConnectionReader(
|
||||
}
|
||||
|
||||
browserConnection.Logger.Tracef("received from browser: %s", string(message))
|
||||
browserConnection.LastBrowserMessageTimeMutex.Lock()
|
||||
browserConnection.LastBrowserMessageTime = time.Now()
|
||||
browserConnection.LastBrowserMessageTimeMutex.Unlock()
|
||||
|
||||
if messageType != websocket.MessageText {
|
||||
browserConnection.Logger.Warnf("received non-text message: %v", messageType)
|
||||
|
Loading…
Reference in New Issue
Block a user