mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
Rebuild the enrichment cache when its pictures were swept
The nightly photo sweep deletes every candidate nobody picked, which is most of them. The cached result still pointed at those files, and the read filtered them out - so the morning after, a place with perfectly available pictures showed an empty column, and kept showing one for the rest of the week the entry lives. A missing candidate now invalidates the whole entry instead of shrinking it.
This commit is contained in:
@@ -300,10 +300,13 @@ export class PlaceEnrichmentService {
|
||||
if (!row || Date.now() - row.fetched_at >= CACHE_TTL_MS) return null;
|
||||
const parsed = JSON.parse(row.payload_json) as CachedEnrichment;
|
||||
|
||||
// A cached candidate is only usable while its bytes are still on disk —
|
||||
// the nightly sweep removes pictures nobody picked, and serving their
|
||||
// proxy URLs afterwards would fill the strip with broken images.
|
||||
// A cached candidate is only usable while its bytes are still on disk, and
|
||||
// the nightly sweep deletes every picture nobody picked — which is most of
|
||||
// them. Treat any loss as a stale entry and rebuild, rather than serving
|
||||
// the survivors: filtering alone would leave the column empty for the rest
|
||||
// of the week for a place that has pictures perfectly available.
|
||||
const photos = parsed.photos.filter((photo) => this.photoCache.get(photo.key));
|
||||
if (photos.length !== parsed.photos.length) return null;
|
||||
return { photos, description: parsed.description ?? null };
|
||||
} catch {
|
||||
return null;
|
||||
|
||||
@@ -491,9 +491,19 @@ describe('result cache', () => {
|
||||
expect(maps.fetchCommonsCandidates).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('ENRICH-023: drops cached candidates whose bytes the nightly sweep removed', async () => {
|
||||
const maps = mapsStub();
|
||||
const cache = cacheStub({ get: vi.fn(() => null) }); // nothing on disk any more
|
||||
it('ENRICH-023: rebuilds when the nightly sweep removed a cached candidate', async () => {
|
||||
// The sweep deletes every picture nobody picked, so this is the normal state
|
||||
// of a cached entry the morning after. Serving the survivors would leave the
|
||||
// column empty for the rest of the week for a place that has pictures.
|
||||
const maps = mapsStub({ fetchCommonsCandidates: vi.fn(async () => [commonsCandidate()]) });
|
||||
let onDisk = false;
|
||||
const cache = cacheStub({
|
||||
get: vi.fn(() => (onDisk ? { photoUrl: '/x', filePath: '/tmp/x', attribution: null } : null)),
|
||||
put: vi.fn(async (key: string) => {
|
||||
onDisk = true;
|
||||
return { photoUrl: `/api/maps/place-photo/${key}/bytes`, filePath: '/tmp/x', attribution: null };
|
||||
}),
|
||||
});
|
||||
mockDbGet.mockImplementation((sql: string) =>
|
||||
String(sql).includes('place_details_cache')
|
||||
? cachedRow([{ key: 'ChIJmuseum~p0', url: '/x', attribution: null, license: null, licenseUrl: null, sourceUrl: null, source: 'wikimedia' }])
|
||||
@@ -502,7 +512,23 @@ describe('result cache', () => {
|
||||
|
||||
const out = await make(maps, cache).enrich(1, REQ);
|
||||
|
||||
expect(out.photos).toEqual([]);
|
||||
expect(maps.fetchCommonsCandidates).toHaveBeenCalled();
|
||||
expect(out.photos).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('ENRICH-023b: keeps serving a cached entry while all its bytes are still there', async () => {
|
||||
const maps = mapsStub();
|
||||
const cache = cacheStub({ get: vi.fn(() => ({ photoUrl: '/x', filePath: '/tmp/x', attribution: null })) });
|
||||
mockDbGet.mockImplementation((sql: string) =>
|
||||
String(sql).includes('place_details_cache')
|
||||
? cachedRow([{ key: 'ChIJmuseum~p0', url: '/x', attribution: null, license: null, licenseUrl: null, sourceUrl: null, source: 'wikimedia' }])
|
||||
: undefined,
|
||||
);
|
||||
|
||||
const out = await make(maps, cache).enrich(1, REQ);
|
||||
|
||||
expect(out.photos).toHaveLength(1);
|
||||
expect(maps.fetchCommonsCandidates).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('ENRICH-024: ignores an unreadable cache row and rebuilds', async () => {
|
||||
|
||||
Reference in New Issue
Block a user