Files
NaviWatcher/internal/musicbrainz/cache.go
Vladimir Zagainov b0f69d3a4f feat: implement rate limiting and caching layer for MusicBrainz provider
- Add golang.org/x/time/rate dependency for token-bucket rate limiting
- Replace custom channel-based rate limiter with rate.NewLimiter(1, 1)
- Add context.Context support to doGet for cancellation
- Add cached_at column to external_releases via migration 005
- Implement cache hit/miss queries with TTL-based filtering
- Add CacheStats type for tracking cached RGIDs
- Update ExternalRelease struct with CachedAt field
- Add rate limiting tests (1 req/sec enforcement, burst behavior)
- Add cache tests (hit, miss, expired, mixed, empty artist)
- Update migration count test for new migration
2026-05-26 12:15:28 +03:00

54 lines
1.5 KiB
Go

package musicbrainz
import (
"fmt"
"time"
"naviwatcher/internal/database"
)
// CacheStats holds the result of a cache lookup for a given artist.
type CacheStats struct {
// CachedRGIDs is the list of RGIDs that are currently cached (within TTL).
CachedRGIDs []string
// CacheHitCount is the number of entries found in cache.
CacheHitCount int
}
// IsCached returns true if the given RGID is in the cached set.
func (cs *CacheStats) IsCached(rgid string) bool {
for _, id := range cs.CachedRGIDs {
if id == rgid {
return true
}
}
return false
}
// GetCachedReleases queries the external_releases table for entries
// belonging to the given artist that were cached within the specified TTL.
// It returns a CacheStats with the list of valid RGIDs already in cache.
func GetCachedReleases(db *database.DB, artistID string, ttl time.Duration) (*CacheStats, error) {
releases, err := database.GetExternalReleasesByArtistWithCache(db, artistID, ttl)
if err != nil {
return nil, fmt.Errorf("get cached releases: %w", err)
}
stats := &CacheStats{}
for _, r := range releases {
stats.CachedRGIDs = append(stats.CachedRGIDs, r.RGID)
stats.CacheHitCount++
}
return stats, nil
}
// IsArtistCacheValid checks whether the cache for an artist is still valid.
// Returns true if any entries exist within the TTL for this artist.
func IsArtistCacheValid(db *database.DB, artistID string, ttl time.Duration) (bool, error) {
stats, err := GetCachedReleases(db, artistID, ttl)
if err != nil {
return false, err
}
return stats.CacheHitCount > 0, nil
}