Retry transient chart detail misses

This commit is contained in:
2569718930@qq.com
2026-06-14 07:42:18 +08:00
parent abe08de769
commit ad1e203adf
2 changed files with 39 additions and 2 deletions
@@ -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 NO_PATCH_CACHED_DETAIL_REFRESH_MS = DASHBOARD_REFRESH_POLICY_MS.observation;
const DETAIL_LOAD_BATCH_DELAY_MS = 0;
const TRANSIENT_DETAIL_RETRY_DELAY_MS = 3_000;
const INITIAL_DETAIL_LOAD_SLOTS = 3;
const DEFERRED_DETAIL_LOAD_DELAY_MS = 1_200;
const DEFERRED_DETAIL_LOAD_GROUP_SIZE = 3;
@@ -792,13 +793,41 @@ export function LiveTemperatureThresholdChart({
setIsHourlyLoading(true);
markDetailRequest("network");
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(() => {
fetchHourlyForecastForCity(city, { resolution: targetResolution })
.then((data) => {
if (cancelled) return;
if (!data) {
markDetailDegraded({ showUserError: true });
scheduleTransientDetailRetry();
return;
}
applySuccessfulHourlyDetail(data);
@@ -809,13 +838,14 @@ export function LiveTemperatureThresholdChart({
}
})
.finally(() => {
if (!cancelled) setIsHourlyLoading(false);
if (!cancelled && !retryScheduled) setIsHourlyLoading(false);
});
}, DETAIL_LOAD_BATCH_DELAY_MS);
return () => {
cancelled = true;
clearTimeout(timer);
if (retryTimer !== null) clearTimeout(retryTimer);
};
}, [
city,
@@ -299,6 +299,13 @@ export async function runTests() {
chartCanvasSourceIncludes(chartSource, "handleRetryDetail"),
"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 applySuccessfulHourlyDetail = useCallback\([\s\S]*?\n \}, \[row\]\);/.exec(chartSource)?.[0] || "";
assert(