fix(beszel): address review findings for live streaming

- Skip toReversed() for live data (already chronological from buffer)
- Reset live buffer on systemId/integration change to avoid stale data
- Throw on unexpected SSE stream end so subscription emits error
- Delete unused time-period.ts config (duplicate of server-side config)
This commit is contained in:
Thomas Camlong committed 2026-06-15 15:15:06 +02:00
1 parent 7e46c71187
commit d13effdda0
4 files changed
+19 -23

No files matched your search

@@ -329,6 +329,9 @@ export class BeszelIntegration extends Integration {
processLine(line);
}
}
if (!signal.aborted) {
throw new Error("Beszel SSE stream ended unexpectedly");
}
} finally {
reader.cancel().catch(() => {});
}
@@ -83,7 +83,8 @@ export const useSystemChartData = (
useMemo(() => {
if (!systemStats) return [];
const fmt = live ? formatTimeLive : formatTime;
return [...systemStats].toReversed().map((r) => ({
const ordered = live ? systemStats : [...systemStats].toReversed();
return ordered.map((r) => ({
time: fmt(r.created),
...mapFn(r.stats),
}));
@@ -123,7 +124,8 @@ export const useDockerChartData = (
const extract = defaultContainerExtractors[metric];
if (!extract) return [];
const fmt = live ? formatTimeLive : formatTime;
return [...containerStats].toReversed().map((record) => {
const ordered = live ? containerStats : [...containerStats].toReversed();
return ordered.map((record) => {
const point: Record<string, unknown> = { time: fmt(record.created) };
for (const name of containerNames) {
point[name] = extract(record.stats.find((c) => c.n === name));
@@ -1,19 +0,0 @@
export const beszelTimePeriods = ["1m", "1h", "12h", "24h", "1w", "30d"] as const;
export type BeszelTimePeriod = (typeof beszelTimePeriods)[number];
export const beszelTimePeriodConfig: Record<
BeszelTimePeriod,
{
beszelStatType: string;
perPage: number;
refetchMs: number;
serverCacheSeconds: number;
}
> = {
"1m": { beszelStatType: "1m", perPage: 60, refetchMs: 0, serverCacheSeconds: 5 },
"1h": { beszelStatType: "1m", perPage: 60, refetchMs: 60_000, serverCacheSeconds: 60 },
"12h": { beszelStatType: "10m", perPage: 72, refetchMs: 300_000, serverCacheSeconds: 300 },
"24h": { beszelStatType: "20m", perPage: 72, refetchMs: 600_000, serverCacheSeconds: 600 },
"1w": { beszelStatType: "120m", perPage: 84, refetchMs: 1_800_000, serverCacheSeconds: 1800 },
"30d": { beszelStatType: "480m", perPage: 90, refetchMs: 3_600_000, serverCacheSeconds: 3600 },
};
@@ -1,6 +1,6 @@
"use client";
import { useCallback, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { clientApi } from "@homarr/api/client";
import type { BeszelContainerStatsRecord, BeszelSystemStatsRecord } from "@homarr/integrations/types";
@@ -12,10 +12,20 @@ interface LiveStatsData {
containerStats: BeszelContainerStatsRecord[];
}
export const useLiveStats = (integrationIds: string[], systemId: string, includeDocker: boolean, enabled: boolean) => {
export const useLiveStats = (
integrationIds: string[],
systemId: string,
includeDocker: boolean,
enabled: boolean,
) => {
const bufferRef = useRef<LiveStatsData>({ systemStats: [], containerStats: [] });
const [data, setData] = useState<LiveStatsData | null>(null);
useEffect(() => {
bufferRef.current = { systemStats: [], containerStats: [] };
setData(null);
}, [systemId, enabled, ...integrationIds]);
const onData = useCallback(
(incoming: { stats: BeszelSystemStatsRecord; containerStats: BeszelContainerStatsRecord | null }) => {
const buf = bufferRef.current;