milestone 27: diagnostics — operational failures land in one curated log, resolved history purgeable
Gates / frontend (push) Successful in 1m33s
Gates / test (push) Successful in 1m48s
Gates / test-aarch64 (push) Successful in 7m10s
Gates / package (push) Successful in 5m31s
Gates / container (push) Successful in 15s
CI / gates (push) Successful in 14m51s
Gates / frontend (push) Successful in 1m33s
Gates / test (push) Successful in 1m48s
Gates / test-aarch64 (push) Successful in 7m10s
Gates / package (push) Successful in 5m31s
Gates / container (push) Successful in 15s
CI / gates (push) Successful in 14m51s
This commit is contained in:
@@ -5,6 +5,8 @@ import type {
|
||||
BlocklistInput,
|
||||
ClientEdit,
|
||||
ClientPrefixInput,
|
||||
DiagnosticsFilter,
|
||||
DiagnosticsPage,
|
||||
ForwardZoneInput,
|
||||
GroupInput,
|
||||
LocalRecordInput,
|
||||
@@ -23,6 +25,10 @@ export const queryKeys = {
|
||||
stats: (period: Period) => ["stats", period] as const,
|
||||
timeseries: (period: Period) => ["stats", "timeseries", period] as const,
|
||||
queriesInfinite: (filter: QueriesFilter) => ["queries", "infinite", filter] as const,
|
||||
diagnosticsInfinite: (filter: DiagnosticsFilter) => ["diagnostics", "infinite", filter] as const,
|
||||
diagnostic: (id: number) => ["diagnostics", "event", id] as const,
|
||||
/** Prefix of every diagnostics entry, page and detail alike; the purge target. */
|
||||
diagnosticsAll: ["diagnostics"] as const,
|
||||
upstreamHealth: (period: Period) => ["upstream-health", period] as const,
|
||||
lookup: (domain: string, groupId?: number) => ["lookup", domain, groupId ?? null] as const,
|
||||
/** Prefix of every `lookup` entry; the invalidation target after any verdict input changes. */
|
||||
@@ -69,6 +75,28 @@ export const queriesInfiniteQuery = (filter: QueriesFilter = {}) =>
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
|
||||
// Keyset pagination on `next_before`, exactly as the query log pages
|
||||
// (handlers/diagnostics.zig copies the /api/queries contract). The active view
|
||||
// polls on healthQuery's cadence because an episode opening is the same news a
|
||||
// health banner carries; a resolved-history page is settled and does not poll.
|
||||
// `enabled` belongs to the factory rather than to a spread at the call site:
|
||||
// spreading the options object loses the page-param type, and the Diagnostics
|
||||
// page turns one of its two sections off whenever a filter excludes it.
|
||||
export const diagnosticsInfiniteQuery = (filter: DiagnosticsFilter = {}, enabled = true) =>
|
||||
infiniteQueryOptions({
|
||||
enabled,
|
||||
queryKey: queryKeys.diagnosticsInfinite(filter),
|
||||
queryFn: ({ pageParam }: { pageParam: number | undefined }) =>
|
||||
api.getDiagnostics(pageParam === undefined ? filter : { ...filter, before: pageParam }),
|
||||
initialPageParam: undefined as number | undefined,
|
||||
getNextPageParam: (last: DiagnosticsPage) => last.next_before ?? undefined,
|
||||
placeholderData: keepPreviousData,
|
||||
refetchInterval: filter.state === "active" ? 10_000 : undefined,
|
||||
});
|
||||
|
||||
export const diagnosticQuery = (id: number) =>
|
||||
queryOptions({ queryKey: queryKeys.diagnostic(id), queryFn: () => api.getDiagnostic(id) });
|
||||
|
||||
// The period is part of the key: the upstream aggregates are ranged like the
|
||||
// stats ones, so the picker has to refetch them rather than reuse a cached
|
||||
// window under a new label.
|
||||
@@ -112,6 +140,19 @@ export const settingsQuery = () => queryOptions({ queryKey: queryKeys.settings,
|
||||
// Group membership and names feed lookup verdicts and the group columns on
|
||||
// clients, prefixes and rules, hence the wide invalidation on group mutations.
|
||||
|
||||
// Both purges invalidate the whole `diagnostics` prefix rather than one page
|
||||
// key: the resolved list, the active list (whose `active` counts ride along) and
|
||||
// the detail query of the row just deleted all describe the table that changed.
|
||||
export const diagnosticPurgeMutation = (qc: QueryClient) => ({
|
||||
mutationFn: (id: number) => api.purgeDiagnostic(id),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.diagnosticsAll }),
|
||||
});
|
||||
|
||||
export const diagnosticsPurgeResolvedMutation = (qc: QueryClient) => ({
|
||||
mutationFn: () => api.purgeResolvedDiagnostics(),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.diagnosticsAll }),
|
||||
});
|
||||
|
||||
function invalidateGroupWorld(qc: QueryClient): Promise<unknown> {
|
||||
return Promise.all([
|
||||
qc.invalidateQueries({ queryKey: queryKeys.groups }),
|
||||
|
||||
Reference in New Issue
Block a user