package store import ( "context" "fmt" "time" "github.com/gorilla/sessions" ) var defaultInterval = time.Minute * 5 // Cleanup runs a background goroutine every interval that deletes expired // sessions from the database. func (db *PGStore) Cleanup(interval time.Duration) (chan<- struct{}, <-chan struct{}) { if interval <= 0 { interval = defaultInterval } quit, done := make(chan struct{}), make(chan struct{}) go db.cleanup(interval, quit, done) return quit, done } // StopCleanup stops the background cleanup from running. func (db *PGStore) StopCleanup(quit chan<- struct{}, done <-chan struct{}) { quit <- struct{}{} <-done } // cleanup deletes expired sessions at set intervals. func (db *PGStore) cleanup(interval time.Duration, quit <-chan struct{}, done chan<- struct{}) { ticker := time.NewTicker(interval) defer func() { ticker.Stop() }() for { select { case <-quit: // Handle the quit signal. done <- struct{}{} return case <-ticker.C: // Delete expired sessions on each tick. var count int rows, err := db.DbPool.QueryContext(context.Background(), "SELECT key FROM http_sessions WHERE expires_on < now()") if err != nil { db.log.Error(err, "pgstore: unable to get expired sessions") done <- struct{}{} return } for rows.Next() { var id string if err := rows.Scan(&id); err != nil { db.log.Error(err, "an error occurred scanning expired session") continue } sess := sessions.NewSession(db, SessionIdentifier) sess.ID = id if err := db.load(sess); err != nil { db.log.Error(err, "failed to load session", "operation_name", CleanupExpiredSessionOp) continue } db.log.Info("deleting expired session", enrichLogWithSession(CleanupExpiredSessionOp, sess)...) count++ } err = db.deleteExpired() if err != nil { db.log.Error(err, "pgstore: unable to delete expired sessions") } else { db.log.Info(fmt.Sprintf("deleted %v expired sessions", count), "operation_name", CleanupExpiredSessionOp) } } } } // deleteExpired deletes expired sessions from the database. func (db *PGStore) deleteExpired() error { _, err := db.DbPool.Exec("DELETE FROM http_sessions WHERE expires_on < now()") return err }