Files
traefikoidc/internal/cache/manager.go
T
lukaszraczylo 9d52f1b018 feat(core): refactor linters config and improve code quality (#119)
- [x] Reorganize golangci-lint configuration with documented disable reasons
- [x] Simplify errcheck and revive linter rules with targeted exclusions
- [x] Pre-compile regex patterns in input_validation.go for performance
- [x] Fix type assertions in memory_shard.go and resp.go with safety checks
- [x] Replace string comparison with EqualFold for case-insensitive matching
- [x] Fix loop variable captures in jwk.go and logout.go
- [x] Change high goroutine log level from Info to Debug in autocleanup.go
- [x] Replace deprecated "cancelled" spelling with "canceled" throughout
- [x] Add nolint annotations for intentional unused parameters
- [x] Improve comment formatting for deprecated functions
- [x] Fix comment spelling: "marshalling" → "marshaling"
- [x] Refactor provider warnings formatting in internal/providers/warnings.go
- [x] Simplify metrics summary building in internal/recovery/metrics.go
- [x] Pre-allocate slice in error_recovery.go GetDegradedServices
- [x] Refactor context cancellation checks in redis.go
2026-01-15 10:40:49 +00:00

280 lines
6.8 KiB
Go

package cache
import (
"sync"
"time"
)
// Manager manages multiple cache instances with singleton pattern
type Manager struct {
logger Logger
tokenCache *Cache
metadataCache *Cache
jwkCache *Cache
sessionCache *Cache
generalCache *Cache
typedToken *TokenCache
typedMetadata *MetadataCache
typedJWK *JWKCache
typedSession *SessionCache
mu sync.RWMutex
}
var (
globalManager *Manager
globalManagerOnce sync.Once
)
// GetGlobalManager returns the singleton cache manager instance
func GetGlobalManager(logger Logger) *Manager {
globalManagerOnce.Do(func() {
globalManager = NewManager(logger)
})
return globalManager
}
// NewManager creates a new cache manager
func NewManager(logger Logger) *Manager {
if logger == nil {
logger = &noOpLogger{}
}
m := &Manager{
logger: logger,
}
// Initialize core caches with appropriate configurations
m.initializeCaches()
return m
}
// initializeCaches creates all cache instances with appropriate configurations
func (m *Manager) initializeCaches() {
// Token cache configuration
tokenConfig := Config{
Type: TypeToken,
MaxSize: 5000,
MaxMemoryBytes: 32 * 1024 * 1024, // 32MB
DefaultTTL: 1 * time.Hour,
CleanupInterval: 5 * time.Minute,
EnableAutoCleanup: true,
EnableMemoryLimit: true,
EnableMetrics: true,
Logger: m.logger,
TokenConfig: &TokenConfig{
BlacklistTTL: 24 * time.Hour,
RefreshTokenTTL: 7 * 24 * time.Hour,
EnableTokenRotation: true,
},
}
m.tokenCache = New(tokenConfig)
m.typedToken = NewTokenCache(m.tokenCache)
// Metadata cache configuration
metadataConfig := Config{
Type: TypeMetadata,
MaxSize: 100,
MaxMemoryBytes: 10 * 1024 * 1024, // 10MB
DefaultTTL: 24 * time.Hour,
CleanupInterval: 30 * time.Minute,
EnableAutoCleanup: true,
EnableMemoryLimit: true,
EnableMetrics: true,
Logger: m.logger,
MetadataConfig: &MetadataConfig{
GracePeriod: 5 * time.Minute,
ExtendedGracePeriod: 15 * time.Minute,
MaxGracePeriod: 1 * time.Hour,
SecurityCriticalMaxGracePeriod: 30 * time.Minute,
SecurityCriticalFields: []string{"issuer", "jwks_uri"},
},
}
m.metadataCache = New(metadataConfig)
m.typedMetadata = NewMetadataCache(m.metadataCache, *metadataConfig.MetadataConfig)
// JWK cache configuration
jwkConfig := Config{
Type: TypeJWK,
MaxSize: 50,
MaxMemoryBytes: 5 * 1024 * 1024, // 5MB
DefaultTTL: 1 * time.Hour,
CleanupInterval: 10 * time.Minute,
EnableAutoCleanup: true,
EnableMemoryLimit: true,
EnableMetrics: true,
Logger: m.logger,
JWKConfig: &JWKConfig{
RefreshInterval: 1 * time.Hour,
MinRefreshTime: 5 * time.Minute,
MaxKeyAge: 24 * time.Hour,
},
}
m.jwkCache = New(jwkConfig)
m.typedJWK = NewJWKCache(m.jwkCache)
// Session cache configuration
sessionConfig := Config{
Type: TypeSession,
MaxSize: 10000,
MaxMemoryBytes: 64 * 1024 * 1024, // 64MB
DefaultTTL: 30 * time.Minute,
CleanupInterval: 5 * time.Minute,
EnableAutoCleanup: true,
EnableMemoryLimit: true,
EnableMetrics: true,
Logger: m.logger,
}
m.sessionCache = New(sessionConfig)
m.typedSession = NewSessionCache(m.sessionCache)
// General cache configuration
generalConfig := Config{
Type: TypeGeneral,
MaxSize: 1000,
MaxMemoryBytes: 16 * 1024 * 1024, // 16MB
DefaultTTL: 10 * time.Minute,
CleanupInterval: 5 * time.Minute,
EnableAutoCleanup: true,
EnableMemoryLimit: true,
EnableMetrics: true,
Logger: m.logger,
}
m.generalCache = New(generalConfig)
}
// GetTokenCache returns the token cache instance
func (m *Manager) GetTokenCache() *TokenCache {
m.mu.RLock()
defer m.mu.RUnlock()
return m.typedToken
}
// GetMetadataCache returns the metadata cache instance
func (m *Manager) GetMetadataCache() *MetadataCache {
m.mu.RLock()
defer m.mu.RUnlock()
return m.typedMetadata
}
// GetJWKCache returns the JWK cache instance
func (m *Manager) GetJWKCache() *JWKCache {
m.mu.RLock()
defer m.mu.RUnlock()
return m.typedJWK
}
// GetSessionCache returns the session cache instance
func (m *Manager) GetSessionCache() *SessionCache {
m.mu.RLock()
defer m.mu.RUnlock()
return m.typedSession
}
// GetGeneralCache returns the general cache instance
func (m *Manager) GetGeneralCache() *Cache {
m.mu.RLock()
defer m.mu.RUnlock()
return m.generalCache
}
// GetRawTokenCache returns the raw token cache for compatibility
func (m *Manager) GetRawTokenCache() *Cache {
m.mu.RLock()
defer m.mu.RUnlock()
return m.tokenCache
}
// GetRawMetadataCache returns the raw metadata cache for compatibility
func (m *Manager) GetRawMetadataCache() *Cache {
m.mu.RLock()
defer m.mu.RUnlock()
return m.metadataCache
}
// GetRawJWKCache returns the raw JWK cache for compatibility
func (m *Manager) GetRawJWKCache() *Cache {
m.mu.RLock()
defer m.mu.RUnlock()
return m.jwkCache
}
// GetStats returns statistics for all caches
func (m *Manager) GetStats() map[string]map[string]interface{} {
m.mu.RLock()
defer m.mu.RUnlock()
return map[string]map[string]interface{}{
"token": m.tokenCache.GetStats(),
"metadata": m.metadataCache.GetStats(),
"jwk": m.jwkCache.GetStats(),
"session": m.sessionCache.GetStats(),
"general": m.generalCache.GetStats(),
}
}
// ClearAll clears all cache instances
func (m *Manager) ClearAll() {
m.mu.Lock()
defer m.mu.Unlock()
m.tokenCache.Clear()
m.metadataCache.Clear()
m.jwkCache.Clear()
m.sessionCache.Clear()
m.generalCache.Clear()
}
// Close gracefully shuts down all cache instances
func (m *Manager) Close() error {
m.mu.Lock()
defer m.mu.Unlock()
var firstErr error
if err := m.tokenCache.Close(); err != nil {
firstErr = err
}
if err := m.metadataCache.Close(); err != nil && firstErr == nil {
firstErr = err
}
if err := m.jwkCache.Close(); err != nil && firstErr == nil {
firstErr = err
}
if err := m.sessionCache.Close(); err != nil && firstErr == nil {
firstErr = err
}
if err := m.generalCache.Close(); err != nil && firstErr == nil {
firstErr = err
}
return firstErr
}
// CleanupAll runs cleanup on all cache instances
func (m *Manager) CleanupAll() {
m.mu.RLock()
defer m.mu.RUnlock()
m.tokenCache.Cleanup()
m.metadataCache.Cleanup()
m.jwkCache.Cleanup()
m.sessionCache.Cleanup()
m.generalCache.Cleanup()
}
// SetLogger updates the logger for all caches
func (m *Manager) SetLogger(logger Logger) {
m.mu.Lock()
defer m.mu.Unlock()
m.logger = logger
if logger != nil {
m.tokenCache.logger = logger
m.metadataCache.logger = logger
m.jwkCache.logger = logger
m.sessionCache.logger = logger
m.generalCache.logger = logger
}
}