Fetch the enrichment pictures concurrently

The column showed "details could not be loaded" for every place. The endpoint
was answering correctly, just after ten seconds, and the shared axios instance
gives up at eight.

The downloads sat in a loop: five Commons hits meant five round trips and five
decodes in sequence, even though the slot limiter already allows five at once.
Both provider listings now run together and the bytes are fetched concurrently,
which brings a warm request back to about a second.

Candidate keys move with it. They now number the provider's list rather than the
surviving strip, so a picture that fails to download leaves a gap instead of
renumbering the ones behind it - a key has to point at the same file on the next
request or the cached result goes stale against the photo cache.

The client asks for enrichment with a longer timeout, and the Wikimedia calls
carry one of their own: a cold TLS handshake from a fresh container was measured
at eight seconds on its own, and no pictures is a better answer than a request
that never comes back.
This commit is contained in:
Maurice
2026-08-09 23:01:51 +02:00
committed by Maurice
parent b36103d2a9
commit 1f1ed630fc
4 changed files with 113 additions and 45 deletions
+4 -2
View File
@@ -931,11 +931,13 @@ export const mapsApi = {
details: (placeId: string, lang?: string) => apiClient.get(`/maps/details/${encodeURIComponent(placeId)}`, { params: { lang } }).then(r => checkInDev(mapsPlaceDetailsResultSchema, r.data, 'maps.details')),
// Pictures and a description for a place that is being looked at but not yet
// saved. Fans out to several providers server-side, so it takes a signal and
// the caller is expected to abort it when the selection changes.
// the caller is expected to abort it when the selection changes, and a longer
// timeout than the global 8s — a cold Wikimedia connection alone can eat that.
placeEnrichment: (
body: { placeId?: string; lat: number; lng: number; name: string; lang?: string },
signal?: AbortSignal,
) => apiClient.post('/maps/enrichment', body, { signal }).then(r => checkInDev(mapsPlaceEnrichmentResultSchema, r.data, 'maps.placeEnrichment')),
) => apiClient.post('/maps/enrichment', body, { signal, timeout: 25000 })
.then(r => checkInDev(mapsPlaceEnrichmentResultSchema, r.data, 'maps.placeEnrichment')),
// Author + licence for a picture already stored in the photo cache, keyed by
// the cache key embedded in its proxy URL. Local read, no provider call.
placePhotoCredit: (key: string) =>