From 256dcf21589cf9a69c339e72cd06efdd70e619fa Mon Sep 17 00:00:00 2001 From: ogzhanolguncu Date: Thu, 24 Apr 2025 18:24:39 +0300 Subject: [PATCH 1/2] refactor: prevent revalidation --- .../charts/bar-chart/hooks/use-fetch-timeseries.ts | 11 ++++++----- .../charts/line-chart/hooks/use-fetch-timeseries.ts | 11 ++++++----- .../components/controls/components/logs-refresh.tsx | 3 +++ .../components/table/hooks/use-logs-query.ts | 10 +++++----- .../apis/_components/hooks/use-query-timeseries.ts | 9 +++++---- .../components/charts/hooks/use-fetch-timeseries.ts | 9 +++++---- .../components/controls/components/logs-refresh.tsx | 3 +++ .../logs/components/table/hooks/use-logs-query.ts | 9 +++++---- 8 files changed, 38 insertions(+), 27 deletions(-) diff --git a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/charts/bar-chart/hooks/use-fetch-timeseries.ts b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/charts/bar-chart/hooks/use-fetch-timeseries.ts index 33a9eb9cfb..03979a2a2b 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/charts/bar-chart/hooks/use-fetch-timeseries.ts +++ b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/charts/bar-chart/hooks/use-fetch-timeseries.ts @@ -1,6 +1,7 @@ import { formatTimestampForChart } from "@/components/logs/chart/utils/format-timestamp"; import { HISTORICAL_DATA_WINDOW } from "@/components/logs/constants"; import { trpc } from "@/lib/trpc/client"; +import { useQueryTime } from "@/providers/query-time-provider"; import { KEY_VERIFICATION_OUTCOMES } from "@unkey/clickhouse/src/keys/keys"; import { useMemo } from "react"; import { keysOverviewFilterFieldConfig } from "../../../../filters.schema"; @@ -9,12 +10,12 @@ import type { KeysOverviewQueryTimeseriesPayload } from "../query-timeseries.sch export const useFetchVerificationTimeseries = (apiId: string | null) => { const { filters } = useFilters(); - const dateNow = useMemo(() => Date.now(), []); + const { queryTime: timestamp } = useQueryTime(); const queryParams = useMemo(() => { const params: KeysOverviewQueryTimeseriesPayload = { - startTime: dateNow - HISTORICAL_DATA_WINDOW, - endTime: dateNow, + startTime: timestamp - HISTORICAL_DATA_WINDOW, + endTime: timestamp, keyIds: { filters: [] }, outcomes: { filters: [] }, names: { filters: [] }, @@ -102,10 +103,10 @@ export const useFetchVerificationTimeseries = (apiId: string | null) => { }); return params; - }, [filters, dateNow, apiId]); + }, [filters, timestamp, apiId]); const { data, isLoading, isError } = trpc.api.keys.timeseries.useQuery(queryParams, { - refetchInterval: queryParams.endTime === dateNow ? 10_000 : false, + refetchInterval: queryParams.endTime === timestamp ? 10_000 : false, enabled: Boolean(apiId), }); diff --git a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/charts/line-chart/hooks/use-fetch-timeseries.ts b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/charts/line-chart/hooks/use-fetch-timeseries.ts index a0f22edc53..193d64b7df 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/charts/line-chart/hooks/use-fetch-timeseries.ts +++ b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/charts/line-chart/hooks/use-fetch-timeseries.ts @@ -1,6 +1,7 @@ import { formatTimestampForChart } from "@/components/logs/chart/utils/format-timestamp"; import { HISTORICAL_DATA_WINDOW } from "@/components/logs/constants"; import { trpc } from "@/lib/trpc/client"; +import { useQueryTime } from "@/providers/query-time-provider"; import { KEY_VERIFICATION_OUTCOMES } from "@unkey/clickhouse/src/keys/keys"; import { useMemo } from "react"; import { keysOverviewFilterFieldConfig } from "../../../../filters.schema"; @@ -9,12 +10,12 @@ import type { KeysOverviewQueryTimeseriesPayload } from "../../bar-chart/query-t export const useFetchActiveKeysTimeseries = (apiId: string | null) => { const { filters } = useFilters(); - const dateNow = useMemo(() => Date.now(), []); + const { queryTime: timestamp } = useQueryTime(); const queryParams = useMemo(() => { const params: KeysOverviewQueryTimeseriesPayload = { - startTime: dateNow - HISTORICAL_DATA_WINDOW, - endTime: dateNow, + startTime: timestamp - HISTORICAL_DATA_WINDOW, + endTime: timestamp, keyIds: { filters: [] }, outcomes: { filters: [] }, names: { filters: [] }, @@ -102,10 +103,10 @@ export const useFetchActiveKeysTimeseries = (apiId: string | null) => { }); return params; - }, [filters, dateNow, apiId]); + }, [filters, timestamp, apiId]); const { data, isLoading, isError } = trpc.api.keys.activeKeysTimeseries.useQuery(queryParams, { - refetchInterval: queryParams.endTime === dateNow ? 10_000 : false, + refetchInterval: queryParams.endTime === timestamp ? 10_000 : false, enabled: Boolean(apiId), }); diff --git a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/controls/components/logs-refresh.tsx b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/controls/components/logs-refresh.tsx index 8b2ee9fab9..2f6e376b05 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/controls/components/logs-refresh.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/controls/components/logs-refresh.tsx @@ -1,13 +1,16 @@ import { RefreshButton } from "@/components/logs/refresh-button"; import { trpc } from "@/lib/trpc/client"; +import { useQueryTime } from "@/providers/query-time-provider"; import { useFilters } from "../../../hooks/use-filters"; export const LogsRefresh = () => { const { filters } = useFilters(); + const { refreshQueryTime } = useQueryTime(); const { api } = trpc.useUtils(); const hasRelativeFilter = filters.find((f) => f.field === "since"); const handleRefresh = () => { + refreshQueryTime(); api.keys.query.invalidate(); api.keys.timeseries.invalidate(); api.keys.activeKeysTimeseries.invalidate(); diff --git a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/hooks/use-logs-query.ts b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/hooks/use-logs-query.ts index 8dff4f9534..1a44dc986a 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/hooks/use-logs-query.ts +++ b/apps/dashboard/app/(app)/apis/[apiId]/_overview/components/table/hooks/use-logs-query.ts @@ -1,6 +1,7 @@ import { HISTORICAL_DATA_WINDOW } from "@/components/logs/constants"; import { useSort } from "@/components/logs/hooks/use-sort"; import { trpc } from "@/lib/trpc/client"; +import { useQueryTime } from "@/providers/query-time-provider"; import { KEY_VERIFICATION_OUTCOMES, type KeysOverviewLog } from "@unkey/clickhouse/src/keys/keys"; import { useEffect, useMemo, useState } from "react"; import { keysOverviewFilterFieldConfig } from "../../../filters.schema"; @@ -22,14 +23,13 @@ export function useKeysOverviewLogsQuery({ apiId, limit = 50 }: UseLogsQueryPara const historicalLogs = useMemo(() => Array.from(historicalLogsMap.values()), [historicalLogsMap]); - // Required for preventing double trpc call during initial render - const dateNow = useMemo(() => Date.now(), []); + const { queryTime: timestamp } = useQueryTime(); const queryParams = useMemo(() => { const params: KeysQueryOverviewLogsPayload = { limit, - startTime: dateNow - HISTORICAL_DATA_WINDOW, - endTime: dateNow, + startTime: timestamp - HISTORICAL_DATA_WINDOW, + endTime: timestamp, keyIds: [], outcomes: [], identities: [], @@ -108,7 +108,7 @@ export function useKeysOverviewLogsQuery({ apiId, limit = 50 }: UseLogsQueryPara }); return params; - }, [filters, limit, dateNow, apiId, sorts]); + }, [filters, limit, timestamp, apiId, sorts]); // Main query for historical data const { diff --git a/apps/dashboard/app/(app)/apis/_components/hooks/use-query-timeseries.ts b/apps/dashboard/app/(app)/apis/_components/hooks/use-query-timeseries.ts index 41bbab4bf7..8180ec343e 100644 --- a/apps/dashboard/app/(app)/apis/_components/hooks/use-query-timeseries.ts +++ b/apps/dashboard/app/(app)/apis/_components/hooks/use-query-timeseries.ts @@ -1,6 +1,7 @@ import { formatTimestampForChart } from "@/components/logs/chart/utils/format-timestamp"; import { HISTORICAL_DATA_WINDOW } from "@/components/logs/constants"; import { trpc } from "@/lib/trpc/client"; +import { useQueryTime } from "@/providers/query-time-provider"; import { useEffect, useMemo, useState } from "react"; import type { VerificationQueryTimeseriesPayload } from "./query-timeseries.schema"; import { useFilters } from "./use-filters"; @@ -8,13 +9,13 @@ import { useFilters } from "./use-filters"; export const useFetchVerificationTimeseries = (keyspaceId: string | null) => { const [enabled, setEnabled] = useState(false); const { filters } = useFilters(); - const dateNow = useMemo(() => Date.now(), []); + const { queryTime: timestamp } = useQueryTime(); const queryParams = useMemo(() => { const params: VerificationQueryTimeseriesPayload = { keyspaceId: keyspaceId ?? "", - startTime: dateNow - HISTORICAL_DATA_WINDOW, - endTime: dateNow, + startTime: timestamp - HISTORICAL_DATA_WINDOW, + endTime: timestamp, since: "", }; @@ -41,7 +42,7 @@ export const useFetchVerificationTimeseries = (keyspaceId: string | null) => { }); return params; - }, [filters, dateNow, keyspaceId]); + }, [filters, timestamp, keyspaceId]); useEffect(() => { // Implement a 2-second delay before enabling queries to prevent excessive ClickHouse load diff --git a/apps/dashboard/app/(app)/logs/components/charts/hooks/use-fetch-timeseries.ts b/apps/dashboard/app/(app)/logs/components/charts/hooks/use-fetch-timeseries.ts index 34a58a1ad0..80ad4fda31 100644 --- a/apps/dashboard/app/(app)/logs/components/charts/hooks/use-fetch-timeseries.ts +++ b/apps/dashboard/app/(app)/logs/components/charts/hooks/use-fetch-timeseries.ts @@ -1,6 +1,7 @@ import { formatTimestampForChart } from "@/components/logs/chart/utils/format-timestamp"; import { HISTORICAL_DATA_WINDOW } from "@/components/logs/constants"; import { trpc } from "@/lib/trpc/client"; +import { useQueryTime } from "@/providers/query-time-provider"; import { useMemo } from "react"; import type { z } from "zod"; import { useFilters } from "../../../hooks/use-filters"; @@ -9,11 +10,11 @@ import type { queryTimeseriesPayload } from "../query-timeseries.schema"; export const useFetchTimeseries = () => { const { filters } = useFilters(); - const dateNow = useMemo(() => Date.now(), []); + const { queryTime: timestamp } = useQueryTime(); const queryParams = useMemo(() => { const params: z.infer = { - startTime: dateNow - HISTORICAL_DATA_WINDOW, - endTime: dateNow, + startTime: timestamp - HISTORICAL_DATA_WINDOW, + endTime: timestamp, host: { filters: [] }, method: { filters: [] }, path: { filters: [] }, @@ -88,7 +89,7 @@ export const useFetchTimeseries = () => { }); return params; - }, [filters, dateNow]); + }, [filters, timestamp]); const { data, isLoading, isError } = trpc.logs.queryTimeseries.useQuery(queryParams, { refetchInterval: queryParams.endTime ? false : 10_000, diff --git a/apps/dashboard/app/(app)/logs/components/controls/components/logs-refresh.tsx b/apps/dashboard/app/(app)/logs/components/controls/components/logs-refresh.tsx index e9e2f483bf..9c924c6209 100644 --- a/apps/dashboard/app/(app)/logs/components/controls/components/logs-refresh.tsx +++ b/apps/dashboard/app/(app)/logs/components/controls/components/logs-refresh.tsx @@ -1,15 +1,18 @@ import { RefreshButton } from "@/components/logs/refresh-button"; import { trpc } from "@/lib/trpc/client"; +import { useQueryTime } from "@/providers/query-time-provider"; import { useLogsContext } from "../../../context/logs"; import { useFilters } from "../../../hooks/use-filters"; export const LogsRefresh = () => { const { toggleLive, isLive } = useLogsContext(); + const { refreshQueryTime } = useQueryTime(); const { filters } = useFilters(); const { logs } = trpc.useUtils(); const hasRelativeFilter = filters.find((f) => f.field === "since"); const handleRefresh = () => { + refreshQueryTime(); logs.queryLogs.invalidate(); logs.queryTimeseries.invalidate(); }; diff --git a/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.ts b/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.ts index ac5382f727..5bad52e4cc 100644 --- a/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.ts +++ b/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.ts @@ -1,5 +1,6 @@ import { HISTORICAL_DATA_WINDOW } from "@/components/logs/constants"; import { trpc } from "@/lib/trpc/client"; +import { useQueryTime } from "@/providers/query-time-provider"; import type { Log } from "@unkey/clickhouse/src/logs"; import { useCallback, useEffect, useMemo, useState } from "react"; import type { z } from "zod"; @@ -26,6 +27,7 @@ export function useLogsQuery({ const { filters } = useFilters(); const queryClient = trpc.useUtils(); + const { queryTime: timestamp } = useQueryTime(); const realtimeLogs = useMemo(() => { return sortLogs(Array.from(realtimeLogsMap.values())); @@ -34,12 +36,11 @@ export function useLogsQuery({ const historicalLogs = useMemo(() => Array.from(historicalLogsMap.values()), [historicalLogsMap]); //Required for preventing double trpc call during initial render - const dateNow = useMemo(() => Date.now(), []); const queryParams = useMemo(() => { const params: z.infer = { limit, - startTime: dateNow - HISTORICAL_DATA_WINDOW, - endTime: dateNow, + startTime: timestamp - HISTORICAL_DATA_WINDOW, + endTime: timestamp, host: { filters: [] }, requestId: { filters: [] }, method: { filters: [] }, @@ -127,7 +128,7 @@ export function useLogsQuery({ }); return params; - }, [filters, limit, dateNow]); + }, [filters, limit, timestamp]); // Main query for historical data const { From 6e07304c9ce420169c5c8c68c9216c14e32ad1c1 Mon Sep 17 00:00:00 2001 From: ogzhanolguncu Date: Thu, 24 Apr 2025 18:51:03 +0300 Subject: [PATCH 2/2] fix: broken test --- .../logs/components/table/hooks/use-logs-query.test.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.test.ts b/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.test.ts index 9d4176fabe..1750654b2a 100644 --- a/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.test.ts +++ b/apps/dashboard/app/(app)/logs/components/table/hooks/use-logs-query.test.ts @@ -6,6 +6,14 @@ import { useLogsQuery } from "./use-logs-query"; let mockFilters: any[] = []; const mockDate = 1706024400000; +vi.mock("@/providers/query-time-provider", () => ({ + QueryTimeProvider: ({ children }: { children: React.ReactNode }) => children, + useQueryTime: () => ({ + queryTime: new Date(mockDate), + refreshQueryTime: vi.fn(), + }), +})); + vi.mock("@/lib/trpc/client", () => { const useInfiniteQuery = vi.fn().mockReturnValue({ data: null, @@ -71,7 +79,7 @@ describe("useLogsQuery filter processing", () => { { field: "host", operator: "is", value: {} }, ]; renderHook(() => useLogsQuery()); - expect(consoleMock).toHaveBeenCalledTimes(3); + expect(consoleMock).toHaveBeenCalledTimes(6); }); it("handles time-based filters", () => {