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
This commit is contained in:
2026-05-26 12:15:28 +03:00
parent 674daed93b
commit b0f69d3a4f
10 changed files with 518 additions and 119 deletions

View File

@@ -115,6 +115,10 @@ func (db *DB) migrate() error {
PRIMARY KEY (rgid, sent_at)
);`,
},
{
name: "005_add_cached_at_to_external_releases",
sql: `ALTER TABLE external_releases ADD COLUMN cached_at DATETIME;`,
},
}
for _, m := range migrations {
@@ -177,12 +181,13 @@ type LocalAlbum struct {
// ExternalRelease represents a row in the external_releases table.
type ExternalRelease struct {
RGID string `json:"rgid"`
ArtistID string `json:"artist_id"`
Title string `json:"title"`
Type string `json:"type"`
ReleaseDate string `json:"release_date"`
IsIgnored bool `json:"is_ignored"`
RGID string `json:"rgid"`
ArtistID string `json:"artist_id"`
Title string `json:"title"`
Type string `json:"type"`
ReleaseDate string `json:"release_date"`
IsIgnored bool `json:"is_ignored"`
CachedAt time.Time `json:"cached_at"`
}
// NotificationSent represents a row in the notifications_sent table.