feat(web): shared Postgres read-through cache for MusicBrainz (ApiCache)
Reopening an artist (discography), an album (tracklist), or repeating a lookup re-hit MusicBrainz every time with no cache and no throttle. Adds a generic Postgres-backed read-through cache keyed on the LOGICAL operation (not the request URL) so the worker and web app share entries. - New ApiCache(key, json, fetchedAt) model + migration (generic name so the Last.fm browse cache can ride the same table). - lib/apicache.ts cached(): read-through, TTL from fetchedAt (tunable, no migration), serve-stale-on-outage, never caches null. - Wrap the high-level MB fns with logical keys + TTLs: discography & tracklists & artist-name 30d, searchReleaseGroup 7d, searchArtists 1d. Search keys normalized (trim+lowercase) to match the worker byte-for-byte. - album-modal: a session-scoped Map<rgMbid,Track[]> so reopening is instant with zero network (complements the DB cache). - Test setup clears ApiCache between tests. web 147 tests, tsc + build clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "ApiCache" (
|
||||
"key" TEXT NOT NULL,
|
||||
"json" JSONB NOT NULL,
|
||||
"fetchedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "ApiCache_pkey" PRIMARY KEY ("key")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ApiCache_fetchedAt_idx" ON "ApiCache"("fetchedAt");
|
||||
@@ -182,3 +182,15 @@ model ScanWorkItem {
|
||||
@@unique([scanId, path])
|
||||
@@index([scanId, done, artist, album])
|
||||
}
|
||||
|
||||
// Generic read-through cache for external API responses shared by web + worker (keyed on
|
||||
// the LOGICAL operation, not the request URL, so both processes share entries). TTL is
|
||||
// applied at read time from fetchedAt in code (no expiresAt column → tunable, no migration).
|
||||
// Named generically so the Last.fm browse cache can ride the same table.
|
||||
model ApiCache {
|
||||
key String @id
|
||||
json Json
|
||||
fetchedAt DateTime @default(now())
|
||||
|
||||
@@index([fetchedAt])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user