Skip to content

Commit bd57e80

Browse files
committed
fix(webapp): expire stale live metric responses
1 parent ac5d061 commit bd57e80

4 files changed

Lines changed: 39 additions & 15 deletions

File tree

  • apps/webapp/app
    • hooks
    • routes
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.queues_.$queueParam
      • _app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.queues
      • resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam

apps/webapp/app/hooks/useMetricResourceQuery.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,25 @@ export type MetricResourceTimeRange = {
1313
to: string | null;
1414
};
1515

16+
export function useIsMetricResponseFresh(
17+
responseReceivedAt: number | null,
18+
dataTimestamp: number,
19+
maxAgeMs: number
20+
) {
21+
const expiresAt =
22+
responseReceivedAt !== null && Number.isFinite(dataTimestamp) ? dataTimestamp + maxAgeMs : null;
23+
const [expiredAt, setExpiredAt] = useState<number | null>(null);
24+
25+
useEffect(() => {
26+
if (expiresAt === null) return;
27+
28+
const timeout = setTimeout(() => setExpiredAt(expiresAt), Math.max(0, expiresAt - Date.now()));
29+
return () => clearTimeout(timeout);
30+
}, [expiresAt]);
31+
32+
return expiresAt !== null && expiredAt !== expiresAt;
33+
}
34+
1635
export type MetricResourceQueryOptions = {
1736
organizationId: string;
1837
projectId: string;

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.queues/route.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ import { ChartCard } from "~/components/primitives/charts/ChartCard";
7474
import { ChartSyncProvider } from "~/components/primitives/charts/ChartSyncContext";
7575
import { useZoomToTimeFilter } from "~/hooks/useZoomToTimeFilter";
7676
import {
77+
useIsMetricResponseFresh,
7778
useMetricResourceQuery,
7879
type MetricResourceTimeRange,
7980
} from "~/hooks/useMetricResourceQuery";
@@ -438,13 +439,12 @@ function QueuesWithMetricsView() {
438439
// client-side nav-back (responseCache), or a quiet env whose latest bucket is minutes old, must
439440
// not override the loader's Redis-exact live values with a stale count.
440441
const lastLiveBucketMs = lastLiveBlockRow ? tileTimeToMs(lastLiveBlockRow.t) : NaN;
441-
const freshLiveBlockRow =
442-
responseReceivedAt !== null &&
443-
lastLiveBlockRow &&
444-
Number.isFinite(lastLiveBucketMs) &&
445-
responseReceivedAt - lastLiveBucketMs < LIVE_GAUGE_FRESH_MS
446-
? lastLiveBlockRow
447-
: null;
442+
const liveBlockIsFresh = useIsMetricResponseFresh(
443+
responseReceivedAt,
444+
lastLiveBucketMs,
445+
LIVE_GAUGE_FRESH_MS
446+
);
447+
const freshLiveBlockRow = lastLiveBlockRow && liveBlockIsFresh ? lastLiveBlockRow : null;
448448
const envQueuedLive = freshLiveBlockRow
449449
? tileNumber(freshLiveBlockRow.env_queued)
450450
: environment.queued;

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.queues_.$queueParam/route.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
toNumber,
3434
useQueueMetric,
3535
} from "~/components/queues/QueueMetricCards";
36+
import { useIsMetricResponseFresh } from "~/hooks/useMetricResourceQuery";
3637
import { findProjectBySlug } from "~/models/project.server";
3738
import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server";
3839
import { QueueRetrievePresenter } from "~/presenters/v3/QueueRetrievePresenter.server";
@@ -1137,10 +1138,11 @@ function QueueStats({
11371138
// Redis/PG value instead of lingering on a stale count.
11381139
const latest = liveRows.length > 0 ? liveRows[liveRows.length - 1] : undefined;
11391140
const latestBucketMs = latest ? clickhouseTimeToMs(latest.t) : NaN;
1140-
const liveFresh =
1141-
responseReceivedAt !== null &&
1142-
Number.isFinite(latestBucketMs) &&
1143-
responseReceivedAt - latestBucketMs < LIVE_GAUGE_FRESH_MS;
1141+
const liveFresh = useIsMetricResponseFresh(
1142+
responseReceivedAt,
1143+
latestBucketMs,
1144+
LIVE_GAUGE_FRESH_MS
1145+
);
11441146
const fresh = latest && liveFresh ? latest : undefined;
11451147
const runningLive = fresh ? toNumber(fresh.running) : null;
11461148
const queuedLive = fresh ? toNumber(fresh.queued) : null;

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ import { useEnvironment } from "~/hooks/useEnvironment";
9191
import { useOrganization } from "~/hooks/useOrganizations";
9292
import { useProject } from "~/hooks/useProject";
9393
import { useSearchParams } from "~/hooks/useSearchParam";
94+
import { useIsMetricResponseFresh } from "~/hooks/useMetricResourceQuery";
9495
import { useHasAdminAccess } from "~/hooks/useUser";
9596
import { redirectWithErrorMessage } from "~/models/message.server";
9697
import {
@@ -1319,10 +1320,12 @@ function WaitingInQueueBlock({
13191320
const latest = liveRows.length > 0 ? liveRows[liveRows.length - 1] : undefined;
13201321
const latestBucketMs = latest ? clickhouseTimeToMs(latest.t) : NaN;
13211322
const now = responseReceivedAt ?? loadedAt;
1322-
const fresh =
1323-
latest && Number.isFinite(latestBucketMs) && now - latestBucketMs < LIVE_GAUGE_FRESH_MS
1324-
? latest
1325-
: undefined;
1323+
const liveFresh = useIsMetricResponseFresh(
1324+
responseReceivedAt,
1325+
latestBucketMs,
1326+
LIVE_GAUGE_FRESH_MS
1327+
);
1328+
const fresh = latest && liveFresh ? latest : undefined;
13261329

13271330
const key = waiting.concurrencyKey;
13281331
const running = fresh ? toNumber(fresh.running) : waiting.running;

0 commit comments

Comments
 (0)