Retry transient chart detail misses
This commit is contained in:
@@ -64,6 +64,7 @@ const PROBABILITY_REFRESH_AFTER_PATCH_MS = DASHBOARD_REFRESH_POLICY_MS.metar;
|
|||||||
const FOREGROUND_FULL_DETAIL_REFRESH_DEDUP_MS = 90_000;
|
const FOREGROUND_FULL_DETAIL_REFRESH_DEDUP_MS = 90_000;
|
||||||
const NO_PATCH_CACHED_DETAIL_REFRESH_MS = DASHBOARD_REFRESH_POLICY_MS.observation;
|
const NO_PATCH_CACHED_DETAIL_REFRESH_MS = DASHBOARD_REFRESH_POLICY_MS.observation;
|
||||||
const DETAIL_LOAD_BATCH_DELAY_MS = 0;
|
const DETAIL_LOAD_BATCH_DELAY_MS = 0;
|
||||||
|
const TRANSIENT_DETAIL_RETRY_DELAY_MS = 3_000;
|
||||||
const INITIAL_DETAIL_LOAD_SLOTS = 3;
|
const INITIAL_DETAIL_LOAD_SLOTS = 3;
|
||||||
const DEFERRED_DETAIL_LOAD_DELAY_MS = 1_200;
|
const DEFERRED_DETAIL_LOAD_DELAY_MS = 1_200;
|
||||||
const DEFERRED_DETAIL_LOAD_GROUP_SIZE = 3;
|
const DEFERRED_DETAIL_LOAD_GROUP_SIZE = 3;
|
||||||
@@ -792,13 +793,41 @@ export function LiveTemperatureThresholdChart({
|
|||||||
setIsHourlyLoading(true);
|
setIsHourlyLoading(true);
|
||||||
markDetailRequest("network");
|
markDetailRequest("network");
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
|
let retryScheduled = false;
|
||||||
|
let retryTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
||||||
|
const scheduleTransientDetailRetry = () => {
|
||||||
|
retryScheduled = true;
|
||||||
|
markDetailDegraded();
|
||||||
|
retryTimer = setTimeout(() => {
|
||||||
|
if (cancelled) return;
|
||||||
|
markDetailRequest("network");
|
||||||
|
fetchHourlyForecastForCity(city, { bypassLocalCache: true, resolution: targetResolution })
|
||||||
|
.then((data) => {
|
||||||
|
if (cancelled) return;
|
||||||
|
if (!data) {
|
||||||
|
markDetailDegraded({ showUserError: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
applySuccessfulHourlyDetail(data);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!cancelled) {
|
||||||
|
markDetailDegraded({ showUserError: true });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
if (!cancelled) setIsHourlyLoading(false);
|
||||||
|
});
|
||||||
|
}, TRANSIENT_DETAIL_RETRY_DELAY_MS);
|
||||||
|
};
|
||||||
|
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
fetchHourlyForecastForCity(city, { resolution: targetResolution })
|
fetchHourlyForecastForCity(city, { resolution: targetResolution })
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
markDetailDegraded({ showUserError: true });
|
scheduleTransientDetailRetry();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
applySuccessfulHourlyDetail(data);
|
applySuccessfulHourlyDetail(data);
|
||||||
@@ -809,13 +838,14 @@ export function LiveTemperatureThresholdChart({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
if (!cancelled) setIsHourlyLoading(false);
|
if (!cancelled && !retryScheduled) setIsHourlyLoading(false);
|
||||||
});
|
});
|
||||||
}, DETAIL_LOAD_BATCH_DELAY_MS);
|
}, DETAIL_LOAD_BATCH_DELAY_MS);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
|
if (retryTimer !== null) clearTimeout(retryTimer);
|
||||||
};
|
};
|
||||||
}, [
|
}, [
|
||||||
city,
|
city,
|
||||||
|
|||||||
@@ -299,6 +299,13 @@ export async function runTests() {
|
|||||||
chartCanvasSourceIncludes(chartSource, "handleRetryDetail"),
|
chartCanvasSourceIncludes(chartSource, "handleRetryDetail"),
|
||||||
"city detail charts should show stale cache first and expose a retryable unavailable state",
|
"city detail charts should show stale cache first and expose a retryable unavailable state",
|
||||||
);
|
);
|
||||||
|
assert(
|
||||||
|
chartSource.includes("TRANSIENT_DETAIL_RETRY_DELAY_MS") &&
|
||||||
|
chartSource.includes("scheduleTransientDetailRetry") &&
|
||||||
|
chartSource.includes("fetchHourlyForecastForCity(city, { bypassLocalCache: true, resolution: targetResolution })") &&
|
||||||
|
chartSource.includes("!retryScheduled"),
|
||||||
|
"cold partial detail-batch misses should stay in loading state and retry cached detail once before showing unavailable",
|
||||||
|
);
|
||||||
const successfulHourlyDetailBlock =
|
const successfulHourlyDetailBlock =
|
||||||
/const applySuccessfulHourlyDetail = useCallback\([\s\S]*?\n \}, \[row\]\);/.exec(chartSource)?.[0] || "";
|
/const applySuccessfulHourlyDetail = useCallback\([\s\S]*?\n \}, \[row\]\);/.exec(chartSource)?.[0] || "";
|
||||||
assert(
|
assert(
|
||||||
|
|||||||
Reference in New Issue
Block a user