fix(usage-stats): avoid partial stats on initial SSE race
Skip creating partial stats from SSE before the initial REST load completes, keeping real-time merges limited to existing full stats. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -204,6 +204,7 @@ export default function UsageStats({ period: periodProp, setPeriod: setPeriodPro
|
|||||||
const [providers, setProviders] = useState([]);
|
const [providers, setProviders] = useState([]);
|
||||||
const [periodLocal, setPeriodLocal] = useState("today");
|
const [periodLocal, setPeriodLocal] = useState("today");
|
||||||
const isInitialLoad = useRef(true);
|
const isInitialLoad = useRef(true);
|
||||||
|
const hasLoadedStats = useRef(false);
|
||||||
const period = periodProp ?? periodLocal;
|
const period = periodProp ?? periodLocal;
|
||||||
const setPeriod = setPeriodProp ?? setPeriodLocal;
|
const setPeriod = setPeriodProp ?? setPeriodLocal;
|
||||||
|
|
||||||
@@ -242,14 +243,17 @@ export default function UsageStats({ period: periodProp, setPeriod: setPeriodPro
|
|||||||
fetch(`/api/usage/stats?period=${period}`)
|
fetch(`/api/usage/stats?period=${period}`)
|
||||||
.then((r) => r.ok ? r.json() : null)
|
.then((r) => r.ok ? r.json() : null)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data) setStats((prev) => ({ ...prev, ...data }));
|
if (data) {
|
||||||
|
hasLoadedStats.current = true;
|
||||||
|
setStats((prev) => ({ ...prev, ...data }));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setFetching(false);
|
setFetching(false);
|
||||||
});
|
});
|
||||||
}, [period]); // eslint-disable-line react-hooks/exhaustive-deps
|
}, [period]);
|
||||||
|
|
||||||
// SSE connection - real-time updates for activeRequests + recentRequests only
|
// SSE connection - real-time updates for activeRequests + recentRequests only
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -259,14 +263,17 @@ export default function UsageStats({ period: periodProp, setPeriod: setPeriodPro
|
|||||||
try {
|
try {
|
||||||
const data = JSON.parse(e.data);
|
const data = JSON.parse(e.data);
|
||||||
// Always merge only real-time fields, never overwrite full stats from REST
|
// Always merge only real-time fields, never overwrite full stats from REST
|
||||||
setStats((prev) => ({
|
setStats((prev) => {
|
||||||
...(prev || {}),
|
if (!prev) return prev;
|
||||||
activeRequests: data.activeRequests,
|
return {
|
||||||
recentRequests: data.recentRequests,
|
...prev,
|
||||||
errorProvider: data.errorProvider,
|
activeRequests: data.activeRequests,
|
||||||
pending: data.pending,
|
recentRequests: data.recentRequests,
|
||||||
}));
|
errorProvider: data.errorProvider,
|
||||||
setLoading(false);
|
pending: data.pending,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (hasLoadedStats.current) setLoading(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("[SSE CLIENT] parse error:", err);
|
console.error("[SSE CLIENT] parse error:", err);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user