Fix duplicate listings via staged Redis cache and frontend stream cancellation

Three-pronged fix for duplicate listings appearing in the UI:

1. Backend: Replace direct rpush cache writes with staged population
   (write to temp key, then atomic RENAME to live key). Skip cache
   writes entirely for POI-enriched requests. Clean staging keys on
   invalidation.

2. Frontend: Add AbortController to cancel in-flight streaming requests
   when loadListings is called again, preventing data mixing.

3. Frontend: Deduplicate features by URL during stream accumulation as
   a safety net against any remaining server-side duplicates.
This commit is contained in:
Viktor Barzin 2026-02-09 21:17:30 +00:00
parent 5b8aa98446
commit 73d19e29d5
No known key found for this signature in database
GPG key ID: 0EB088298288D958
5 changed files with 159 additions and 38 deletions

View file

@ -68,7 +68,7 @@ export async function* streamListingGeoJSON(
user: AuthUser,
parameters: ParameterValues,
onProgress?: (progress: StreamingProgress) => void,
options?: { includePoiDistances?: boolean },
options?: { includePoiDistances?: boolean; signal?: AbortSignal },
): AsyncGenerator<PropertyFeature[], void, unknown> {
const params = buildListingParams(parameters);
if (options?.includePoiDistances) {
@ -83,6 +83,7 @@ export async function* streamListingGeoJSON(
headers: {
Authorization: `Bearer ${user.accessToken}`,
},
signal: options?.signal,
});
if (!response.ok) {
@ -99,6 +100,10 @@ export async function* streamListingGeoJSON(
let totalCount = 0;
while (true) {
if (options?.signal?.aborted) {
await reader.cancel();
return;
}
const { done, value } = await reader.read();
if (done) break;