Add idle timeout into session manager

This commit is contained in:
Dan Sosedoff 2022-12-02 14:20:20 -06:00
parent 0a133dc395
commit 16726e2461
No known key found for this signature in database
GPG Key ID: 26186197D282B164
4 changed files with 31 additions and 12 deletions

View File

@ -10,9 +10,10 @@ import (
)
type SessionManager struct {
logger *logrus.Logger
sessions map[string]*client.Client
mu sync.Mutex
logger *logrus.Logger
sessions map[string]*client.Client
mu sync.Mutex
idleTimeout time.Duration
}
func NewSessionManager(logger *logrus.Logger) *SessionManager {
@ -23,6 +24,10 @@ func NewSessionManager(logger *logrus.Logger) *SessionManager {
}
}
func (m *SessionManager) SetIdleTimeout(timeout time.Duration) {
m.idleTimeout = timeout
}
func (m *SessionManager) IDs() []string {
m.mu.Lock()
defer m.mu.Unlock()
@ -79,6 +84,10 @@ func (m *SessionManager) Len() int {
}
func (m *SessionManager) Cleanup() int {
if m.idleTimeout == 0 {
return 0
}
removed := 0
m.logger.Debug("starting idle sessions cleanup")
@ -97,6 +106,8 @@ func (m *SessionManager) Cleanup() int {
}
func (m *SessionManager) RunPeriodicCleanup() {
m.logger.WithField("timeout", m.idleTimeout).Info("session manager cleanup enabled")
for range time.Tick(time.Minute) {
m.Cleanup()
}
@ -106,9 +117,11 @@ func (m *SessionManager) staleSessions() []string {
m.mu.TryLock()
defer m.mu.Unlock()
now := time.Now()
ids := []string{}
for id, conn := range m.sessions {
if conn.IsIdle() {
if now.Sub(conn.LastQueryTime()) > m.idleTimeout {
ids = append(ids, id)
}
}

View File

@ -3,12 +3,12 @@ package api
import (
"sort"
"testing"
"time"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/sosedoff/pgweb/pkg/client"
"github.com/sosedoff/pgweb/pkg/command"
)
func TestSessionManager(t *testing.T) {
@ -60,20 +60,16 @@ func TestSessionManager(t *testing.T) {
})
t.Run("clean up stale sessions", func(t *testing.T) {
defer func() {
command.Opts.ConnectionIdleTimeout = 0
}()
manager := NewSessionManager(logrus.New())
conn := &client.Client{}
manager.Add("foo", conn)
command.Opts.ConnectionIdleTimeout = 0
assert.Equal(t, 1, manager.Len())
assert.Equal(t, 0, manager.Cleanup())
assert.Equal(t, 1, manager.Len())
command.Opts.ConnectionIdleTimeout = 1
conn.Query("select 1")
manager.SetIdleTimeout(time.Minute)
assert.Equal(t, 1, manager.Cleanup())
assert.Equal(t, 0, manager.Len())
assert.True(t, conn.IsClosed())

View File

@ -8,6 +8,7 @@ import (
"regexp"
"strings"
"syscall"
"time"
"github.com/gin-gonic/gin"
"github.com/jessevdk/go-flags"
@ -266,6 +267,7 @@ func Run() {
api.DbSessions = api.NewSessionManager(logger)
if !command.Opts.DisableConnectionIdleTimeout {
api.DbSessions.SetIdleTimeout(time.Minute * time.Duration(command.Opts.ConnectionIdleTimeout))
go api.DbSessions.RunPeriodicCleanup()
}
}

View File

@ -335,6 +335,10 @@ func (client *Client) ServerVersion() string {
}
func (client *Client) query(query string, args ...interface{}) (*Result, error) {
if client.db == nil {
return nil, nil
}
// Update the last usage time
defer func() {
client.lastQueryTime = time.Now().UTC()
@ -366,7 +370,7 @@ func (client *Client) query(query string, args ...interface{}) (*Result, error)
result := Result{
Columns: []string{"Rows Affected"},
Rows: []Row{
Row{affected},
{affected},
},
}
@ -446,6 +450,10 @@ func (c *Client) IsClosed() bool {
return c.closed
}
func (c *Client) LastQueryTime() time.Time {
return c.lastQueryTime
}
func (client *Client) IsIdle() bool {
mins := int(time.Since(client.lastQueryTime).Minutes())