diff --git a/internal/store/pg/sessions.go b/internal/store/pg/sessions.go index 04efb579..d33d2ed1 100644 --- a/internal/store/pg/sessions.go +++ b/internal/store/pg/sessions.go @@ -3,6 +3,7 @@ package pg import ( "database/sql" "encoding/json" + "log/slog" "maps" "strings" "sync" @@ -26,10 +27,35 @@ type PGSessionStore struct { } func NewPGSessionStore(db *sql.DB) *PGSessionStore { - return &PGSessionStore{ + s := &PGSessionStore{ db: db, cache: make(map[string]*store.SessionData), } + s.migrateLegacyWSKeys() + return s +} + +// migrateLegacyWSKeys renames old WS session keys from non-canonical format +// (agent:X:ws-userId-ts) to canonical format (agent:X:ws:direct:ts). +// The last hyphen-delimited segment is the base36 timestamp used as convId. +// Idempotent — no-op if no legacy keys exist. +func (s *PGSessionStore) migrateLegacyWSKeys() { + res, err := s.db.Exec(` + UPDATE sessions + SET session_key = regexp_replace( + session_key, + '^(agent:[^:]+):ws-.+-([^-]+)$', + '\1:ws:direct:\2' + ) + WHERE session_key ~ '^agent:[^:]+:ws-' + `) + if err != nil { + slog.Warn("sessions.migrate_legacy_ws_keys", "error", err) + return + } + if n, _ := res.RowsAffected(); n > 0 { + slog.Info("sessions.migrate_legacy_ws_keys", "migrated", n) + } } func (s *PGSessionStore) GetOrCreate(key string) *store.SessionData {