package service import ( "log" "time" "gorm.io/gorm" "github.com/wangjia/jiu/backend/internal/model" ) // sessionCleanupInterval 清理任务执行周期。 const sessionCleanupInterval = 24 * time.Hour // StartSessionCleanup 启动后台清理 goroutine:启动即跑一次,之后每 24h 跑一次。 // 删除已撤销/已过期的会话行与过旧的失败登录记录,防止表无限膨胀、IP/UA 长期滞留。 // retentionDays<=0 时视为关闭清理(直接返回,不启动 goroutine)。 func StartSessionCleanup(db *gorm.DB, retentionDays int) { if retentionDays <= 0 { log.Printf("[cleanup] session cleanup disabled (retention_days=%d)", retentionDays) return } go func() { cleanupOnce(db, retentionDays) ticker := time.NewTicker(sessionCleanupInterval) defer ticker.Stop() for range ticker.C { cleanupOnce(db, retentionDays) } }() } // cleanupOnce 执行一轮清理,返回各表删除行数(供测试断言)。 func cleanupOnce(db *gorm.DB, retentionDays int) (sessions, attempts int64) { cutoff := time.Now().AddDate(0, 0, -retentionDays) r1 := db.Where( "(revoked_at IS NOT NULL AND revoked_at < ?) OR (refresh_exp_at IS NOT NULL AND refresh_exp_at < ?)", cutoff, cutoff, ).Delete(&model.UserSession{}) if r1.Error != nil { log.Printf("[cleanup] purge user_sessions failed: %v", r1.Error) } r2 := db.Where("created_at < ?", cutoff).Delete(&model.LoginAttempt{}) if r2.Error != nil { log.Printf("[cleanup] purge login_attempts failed: %v", r2.Error) } if r1.RowsAffected > 0 || r2.RowsAffected > 0 { log.Printf("[cleanup] purged %d sessions, %d login_attempts (older than %dd)", r1.RowsAffected, r2.RowsAffected, retentionDays) } return r1.RowsAffected, r2.RowsAffected }